wined3d: Add D3DSI and other opcode masks to the WINED3D namespace.
[wine/wine64.git] / dlls / wined3d / device.c
blobee966b0c4205c60c194445a60e0f1faa80179922
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* 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 D3DCREATESHADEROBJECTINSTANCE(object, type) { \
99 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
100 D3DMEMCHECK(object, pp##type); \
101 object->lpVtbl = &IWineD3D##type##_Vtbl; \
102 object->parent = parent; \
103 object->ref = 1; \
104 object->baseShader.device = (IWineD3DDevice*) This; \
105 *pp##type = (IWineD3D##type *) object; \
108 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
109 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
110 D3DMEMCHECK(object, pp##type); \
111 object->lpVtbl = &IWineD3D##type##_Vtbl; \
112 object->resource.wineD3DDevice = This; \
113 object->resource.parent = parent; \
114 object->resource.resourceType = d3dtype; \
115 object->resource.ref = 1; \
116 object->resource.pool = Pool; \
117 object->resource.format = Format; \
118 object->resource.usage = Usage; \
119 object->resource.size = _size; \
120 /* Check that we have enough video ram left */ \
121 if (Pool == WINED3DPOOL_DEFAULT) { \
122 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
123 WARN("Out of 'bogus' video memory\n"); \
124 HeapFree(GetProcessHeap(), 0, object); \
125 *pp##type = NULL; \
126 return WINED3DERR_OUTOFVIDEOMEMORY; \
128 globalChangeGlRam(_size); \
130 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
131 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
132 FIXME("Out of memory!\n"); \
133 HeapFree(GetProcessHeap(), 0, object); \
134 *pp##type = NULL; \
135 return WINED3DERR_OUTOFVIDEOMEMORY; \
137 *pp##type = (IWineD3D##type *) object; \
138 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
139 TRACE("(%p) : Created resource %p\n", This, object); \
142 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
143 _basetexture.levels = Levels; \
144 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
145 _basetexture.LOD = 0; \
146 _basetexture.dirty = TRUE; \
149 /**********************************************************
150 * Global variable / Constants follow
151 **********************************************************/
152 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
154 /**********************************************************
155 * Utility functions follow
156 **********************************************************/
157 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
158 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
160 float quad_att;
161 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
164 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
165 glMatrixMode(GL_MODELVIEW);
166 glPushMatrix();
167 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
169 /* Diffuse: */
170 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
171 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
172 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
173 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
174 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
175 checkGLcall("glLightfv");
177 /* Specular */
178 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
179 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
180 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
181 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
182 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
183 checkGLcall("glLightfv");
185 /* Ambient */
186 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
187 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
188 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
189 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
190 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
191 checkGLcall("glLightfv");
193 /* Attenuation - Are these right? guessing... */
194 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
195 checkGLcall("glLightf");
196 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
197 checkGLcall("glLightf");
199 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
200 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
201 } else {
202 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
205 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
206 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
207 checkGLcall("glLightf");
209 switch (lightInfo->OriginalParms.Type) {
210 case WINED3DLIGHT_POINT:
211 /* Position */
212 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
213 checkGLcall("glLightfv");
214 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
215 checkGLcall("glLightf");
216 /* FIXME: Range */
217 break;
219 case WINED3DLIGHT_SPOT:
220 /* Position */
221 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
222 checkGLcall("glLightfv");
223 /* Direction */
224 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
225 checkGLcall("glLightfv");
226 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
227 checkGLcall("glLightf");
228 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
229 checkGLcall("glLightf");
230 /* FIXME: Range */
231 break;
233 case WINED3DLIGHT_DIRECTIONAL:
234 /* Direction */
235 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
236 checkGLcall("glLightfv");
237 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
238 checkGLcall("glLightf");
239 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
240 checkGLcall("glLightf");
241 break;
243 default:
244 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
247 /* Restore the modelview matrix */
248 glPopMatrix();
251 /**********************************************************
252 * GLSL helper functions follow
253 **********************************************************/
255 /** Attach a GLSL pixel or vertex shader object to the shader program */
256 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
259 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
260 if (This->stateBlock->glsl_program && shaderObj != 0) {
261 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
262 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
263 checkGLcall("glAttachObjectARB");
267 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
268 * It sets the programId on the current StateBlock (because it should be called
269 * inside of the DrawPrimitive() part of the render loop).
271 * If a program for the given combination does not exist, create one, and store
272 * the program in the list. If it creates a program, it will link the given
273 * objects, too.
275 * We keep the shader programs around on a list because linking
276 * shader objects together is an expensive operation. It's much
277 * faster to loop through a list of pre-compiled & linked programs
278 * each time that the application sets a new pixel or vertex shader
279 * than it is to re-link them together at that time.
281 * The list will be deleted in IWineD3DDevice::Release().
283 void set_glsl_shader_program(IWineD3DDevice *iface) {
285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
286 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
287 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
288 struct glsl_shader_prog_link *curLink = NULL;
289 struct glsl_shader_prog_link *newLink = NULL;
290 struct list *ptr = NULL;
291 GLhandleARB programId = 0;
292 int i;
293 char glsl_name[8];
295 ptr = list_head( &This->glsl_shader_progs );
296 while (ptr) {
297 /* At least one program exists - see if it matches our ps/vs combination */
298 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
299 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
300 /* Existing Program found, use it */
301 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
302 curLink->programId);
303 This->stateBlock->glsl_program = curLink;
304 return;
306 /* This isn't the entry we need - try the next one */
307 ptr = list_next( &This->glsl_shader_progs, ptr );
310 /* If we get to this point, then no matching program exists, so we create one */
311 programId = GL_EXTCALL(glCreateProgramObjectARB());
312 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
314 /* Allocate a new link for the list of programs */
315 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
316 newLink->programId = programId;
317 This->stateBlock->glsl_program = newLink;
319 /* Attach GLSL vshader */
320 if (NULL != vshader && This->vs_selected_mode == SHADER_GLSL) {
321 int i;
322 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
323 char tmp_name[10];
325 TRACE("Attaching vertex shader to GLSL program\n");
326 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
328 /* Bind vertex attributes to a corresponding index number to match
329 * the same index numbers as ARB_vertex_programs (makes loading
330 * vertex attributes simpler). With this method, we can use the
331 * exact same code to load the attributes later for both ARB and
332 * GLSL shaders.
334 * We have to do this here because we need to know the Program ID
335 * in order to make the bindings work, and it has to be done prior
336 * to linking the GLSL program. */
337 for (i = 0; i < max_attribs; ++i) {
338 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
339 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
341 checkGLcall("glBindAttribLocationARB");
342 newLink->vertexShader = vshader;
345 /* Attach GLSL pshader */
346 if (NULL != pshader && This->ps_selected_mode == SHADER_GLSL) {
347 TRACE("Attaching pixel shader to GLSL program\n");
348 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
349 newLink->pixelShader = pshader;
352 /* Link the program */
353 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
354 GL_EXTCALL(glLinkProgramARB(programId));
355 print_glsl_info_log(&GLINFO_LOCATION, programId);
356 list_add_head( &This->glsl_shader_progs, &newLink->entry);
358 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
359 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
360 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
361 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
363 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
364 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
365 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
366 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
369 return;
372 /** Detach the GLSL pixel or vertex shader object from the shader program */
373 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
377 if (shaderObj != 0 && programId != 0) {
378 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
379 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
380 checkGLcall("glDetachObjectARB");
384 /** Delete a GLSL shader program */
385 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
389 if (obj != 0) {
390 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
391 GL_EXTCALL(glDeleteObjectARB(obj));
392 checkGLcall("glDeleteObjectARB");
396 /** Delete the list of linked programs this shader is associated with.
397 * Also at this point, check to see if there are any objects left attached
398 * to each GLSL program. If not, delete the GLSL program object.
399 * This will be run when a device is released. */
400 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
402 struct list *ptr = NULL;
403 struct glsl_shader_prog_link *curLink = NULL;
404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
406 int numAttached = 0;
407 int i;
408 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
409 (one pixel shader and one vertex shader at most) */
411 ptr = list_head( &This->glsl_shader_progs );
412 while (ptr) {
413 /* First, get the current item,
414 * save the link to the next pointer,
415 * detach and delete shader objects,
416 * then de-allocate the list item's memory */
417 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
418 ptr = list_next( &This->glsl_shader_progs, ptr );
420 /* See if this object is still attached to the program - it may have been detached already */
421 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
422 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
423 for (i = 0; i < numAttached; i++) {
424 detach_glsl_shader(iface, objList[i], curLink->programId);
427 delete_glsl_shader_program(iface, curLink->programId);
429 /* Free the uniform locations */
430 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
431 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
433 /* Free the memory for this list item */
434 HeapFree(GetProcessHeap(), 0, curLink);
439 /* Apply the current values to the specified texture stage */
440 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
442 float col[4];
444 union {
445 float f;
446 DWORD d;
447 } tmpvalue;
449 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
450 clamping, MIPLOD, etc. This will work for up to 16 samplers.
453 if (Sampler >= GL_LIMITS(sampler_stages)) {
454 FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
455 return;
457 VTRACE(("Activating appropriate texture state %d\n", Sampler));
458 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
459 ENTER_GL();
460 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
461 checkGLcall("glActiveTextureARB");
462 LEAVE_GL();
463 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
464 } else if (Sampler > 0) {
465 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
466 return;
469 /* TODO: change this to a lookup table
470 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
471 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
472 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
473 especially when there are a number of groups of states. */
475 TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
477 /* 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 */
478 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
479 /* these are the only two supported states that need to be applied */
480 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
481 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
482 #if 0 /* not supported at the moment */
483 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
484 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
485 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
486 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
487 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
488 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
489 APPLY_STATE(WINED3DTSS_RESULTARG);
490 APPLY_STATE(WINED3DTSS_CONSTANT);
491 #endif
492 /* a quick sanity check in case someone forgot to update this function */
493 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
494 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
496 #undef APPLY_STATE
498 /* apply any sampler states that always need applying */
499 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
500 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
501 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
502 GL_TEXTURE_LOD_BIAS_EXT,
503 tmpvalue.f);
504 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
507 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
508 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
509 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
511 /* TODO: NV_POINT_SPRITE */
512 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
513 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
514 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
515 glDisable(GL_POINT_SMOOTH);
517 /* Centre the texture on the vertex */
518 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
519 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
521 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
522 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
523 checkGLcall("glTexEnvf(...)");
524 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
525 glEnable( GL_POINT_SPRITE_ARB );
526 checkGLcall("glEnable(...)");
527 } else {
528 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
529 glDisable( GL_POINT_SPRITE_ARB );
530 checkGLcall("glEnable(...)");
534 TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
537 /**********************************************************
538 * IUnknown parts follows
539 **********************************************************/
541 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
545 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
546 if (IsEqualGUID(riid, &IID_IUnknown)
547 || IsEqualGUID(riid, &IID_IWineD3DBase)
548 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
549 IUnknown_AddRef(iface);
550 *ppobj = This;
551 return S_OK;
553 *ppobj = NULL;
554 return E_NOINTERFACE;
557 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
559 ULONG refCount = InterlockedIncrement(&This->ref);
561 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
562 return refCount;
565 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
567 ULONG refCount = InterlockedDecrement(&This->ref);
569 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
571 if (!refCount) {
572 /* TODO: Clean up all the surfaces and textures! */
573 /* NOTE: You must release the parent if the object was created via a callback
574 ** ***************************/
576 /* Delete any GLSL shader programs that may exist */
577 if (This->vs_selected_mode == SHADER_GLSL ||
578 This->ps_selected_mode == SHADER_GLSL)
579 delete_glsl_shader_list(iface);
581 /* Release the update stateblock */
582 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
583 if(This->updateStateBlock != This->stateBlock)
584 FIXME("(%p) Something's still holding the Update stateblock\n",This);
586 This->updateStateBlock = NULL;
587 { /* because were not doing proper internal refcounts releasing the primary state block
588 causes recursion with the extra checks in ResourceReleased, to avoid this we have
589 to set this->stateBlock = NULL; first */
590 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
591 This->stateBlock = NULL;
593 /* Release the stateblock */
594 if(IWineD3DStateBlock_Release(stateBlock) > 0){
595 FIXME("(%p) Something's still holding the Update stateblock\n",This);
599 if (This->resources != NULL ) {
600 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
601 dumpResources(This->resources);
605 IWineD3D_Release(This->wineD3D);
606 This->wineD3D = NULL;
607 HeapFree(GetProcessHeap(), 0, This);
608 TRACE("Freed device %p\n", This);
609 This = NULL;
611 return refCount;
614 /**********************************************************
615 * IWineD3DDevice implementation follows
616 **********************************************************/
617 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
619 *pParent = This->parent;
620 IUnknown_AddRef(This->parent);
621 return WINED3D_OK;
624 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
625 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
626 GLenum error, glUsage;
627 DWORD vboUsage = object->resource.usage;
628 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
629 WARN("Creating a vbo failed once, not trying again\n");
630 return;
633 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
635 ENTER_GL();
636 /* Make sure that the gl error is cleared. Do not use checkGLcall
637 * here because checkGLcall just prints a fixme and continues. However,
638 * if an error during VBO creation occurs we can fall back to non-vbo operation
639 * with full functionality(but performance loss)
641 while(glGetError() != GL_NO_ERROR);
643 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
644 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
645 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
646 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
647 * to check if the rhw and color values are in the correct format.
650 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
651 error = glGetError();
652 if(object->vbo == 0 || error != GL_NO_ERROR) {
653 WARN("Failed to create a VBO with error %d\n", error);
654 goto error;
657 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
658 error = glGetError();
659 if(error != GL_NO_ERROR) {
660 WARN("Failed to bind the VBO, error %d\n", error);
661 goto error;
664 /* Transformed vertices are horribly inflexible. If the app specifies an
665 * vertex buffer with transformed vertices in default pool without DYNAMIC
666 * usage assume DYNAMIC usage and print a warning. The app will have to update
667 * the vertices regularily for them to be useful
669 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
670 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
671 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
672 vboUsage |= WINED3DUSAGE_DYNAMIC;
675 /* Don't use static, because dx apps tend to update the buffer
676 * quite often even if they specify 0 usage
678 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
679 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
680 TRACE("Gl usage = GL_STREAM_DRAW\n");
681 glUsage = GL_STREAM_DRAW_ARB;
682 break;
683 case D3DUSAGE_WRITEONLY:
684 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
685 glUsage = GL_DYNAMIC_DRAW_ARB;
686 break;
687 case D3DUSAGE_DYNAMIC:
688 TRACE("Gl usage = GL_STREAM_COPY\n");
689 glUsage = GL_STREAM_COPY_ARB;
690 break;
691 default:
692 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
693 glUsage = GL_DYNAMIC_COPY_ARB;
694 break;
697 /* Reserve memory for the buffer. The amount of data won't change
698 * so we are safe with calling glBufferData once with a NULL ptr and
699 * calling glBufferSubData on updates
701 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
702 error = glGetError();
703 if(error != GL_NO_ERROR) {
704 WARN("glBufferDataARB failed with error %d\n", error);
705 goto error;
708 LEAVE_GL();
710 return;
711 error:
712 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
713 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
714 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
715 object->vbo = 0;
716 object->Flags |= VBFLAG_VBOCREATEFAIL;
717 LEAVE_GL();
718 return;
721 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
722 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
723 IUnknown *parent) {
724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
725 IWineD3DVertexBufferImpl *object;
726 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
727 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
728 BOOL conv;
729 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
731 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
732 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
734 if(Size == 0) return WINED3DERR_INVALIDCALL;
736 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
737 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
739 object->fvf = FVF;
741 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
742 * drawStridedFast (half-life 2).
744 * Basically converting the vertices in the buffer is quite expensive, and observations
745 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
746 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
748 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
749 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
750 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
751 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
752 * dx7 apps.
753 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
754 * more. In this call we can convert dx7 buffers too.
756 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
757 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
758 (dxVersion > 7 || !conv) ) {
759 CreateVBO(object);
761 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
762 if(dxVersion == 7 && object->vbo) {
763 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
764 object->resource.allocatedMemory = NULL;
768 return WINED3D_OK;
771 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
772 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
773 HANDLE *sharedHandle, IUnknown *parent) {
774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
775 IWineD3DIndexBufferImpl *object;
776 TRACE("(%p) Creating index buffer\n", This);
778 /* Allocate the storage for the device */
779 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
781 /*TODO: use VBO's */
782 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
783 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
786 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
787 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
788 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
790 return WINED3D_OK;
793 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
796 IWineD3DStateBlockImpl *object;
797 int i, j;
798 HRESULT temp_result;
800 D3DCREATEOBJECTINSTANCE(object, StateBlock)
801 object->blockType = Type;
803 /* Special case - Used during initialization to produce a placeholder stateblock
804 so other functions called can update a state block */
805 if (Type == WINED3DSBT_INIT) {
806 /* Don't bother increasing the reference count otherwise a device will never
807 be freed due to circular dependencies */
808 return WINED3D_OK;
811 temp_result = allocate_shader_constants(object);
812 if (WINED3D_OK != temp_result)
813 return temp_result;
815 /* Otherwise, might as well set the whole state block to the appropriate values */
816 if (This->stateBlock != NULL)
817 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
818 else
819 memset(object->streamFreq, 1, sizeof(object->streamFreq));
821 /* Reset the ref and type after kludging it */
822 object->wineD3DDevice = This;
823 object->ref = 1;
824 object->blockType = Type;
826 TRACE("Updating changed flags appropriate for type %d\n", Type);
828 if (Type == WINED3DSBT_ALL) {
830 TRACE("ALL => Pretend everything has changed\n");
831 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
833 } else if (Type == WINED3DSBT_PIXELSTATE) {
835 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
836 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
838 object->changed.pixelShader = TRUE;
840 /* Pixel Shader Constants */
841 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
842 object->changed.pixelShaderConstantsF[i] = TRUE;
843 for (i = 0; i < MAX_CONST_B; ++i)
844 object->changed.pixelShaderConstantsB[i] = TRUE;
845 for (i = 0; i < MAX_CONST_I; ++i)
846 object->changed.pixelShaderConstantsI[i] = TRUE;
848 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
849 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
851 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
852 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
853 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
856 for (j = 0 ; j < 16; j++) {
857 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
859 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
863 } else if (Type == WINED3DSBT_VERTEXSTATE) {
865 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
866 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
868 object->changed.vertexShader = TRUE;
870 /* Vertex Shader Constants */
871 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
872 object->changed.vertexShaderConstantsF[i] = TRUE;
873 for (i = 0; i < MAX_CONST_B; ++i)
874 object->changed.vertexShaderConstantsB[i] = TRUE;
875 for (i = 0; i < MAX_CONST_I; ++i)
876 object->changed.vertexShaderConstantsI[i] = TRUE;
878 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
879 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
881 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
882 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
883 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
886 for (j = 0 ; j < 16; j++){
887 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
888 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
892 /* Duplicate light chain */
894 PLIGHTINFOEL *src = NULL;
895 PLIGHTINFOEL *dst = NULL;
896 PLIGHTINFOEL *newEl = NULL;
897 src = This->stateBlock->lights;
898 object->lights = NULL;
901 while (src) {
902 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
903 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
904 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
905 newEl->prev = dst;
906 newEl->changed = TRUE;
907 newEl->enabledChanged = TRUE;
908 if (dst == NULL) {
909 object->lights = newEl;
910 } else {
911 dst->next = newEl;
913 dst = newEl;
914 src = src->next;
919 } else {
920 FIXME("Unrecognized state block type %d\n", Type);
923 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
924 return WINED3D_OK;
928 /* ************************************
929 MSDN:
930 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
932 Discard
933 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
935 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.
937 ******************************** */
939 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) {
940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
941 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
942 unsigned int pow2Width, pow2Height;
943 unsigned int Size = 1;
944 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
945 TRACE("(%p) Create surface\n",This);
947 /** FIXME: Check ranges on the inputs are valid
948 * MSDN
949 * MultisampleQuality
950 * [in] Quality level. The valid range is between zero and one less than the level
951 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
952 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
953 * values of paired render targets, depth stencil surfaces, and the MultiSample type
954 * must all match.
955 *******************************/
959 * TODO: Discard MSDN
960 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
962 * If this flag is set, the contents of the depth stencil buffer will be
963 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
964 * with a different depth surface.
966 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
967 ***************************/
969 if(MultisampleQuality < 0) {
970 FIXME("Invalid multisample level %d\n", MultisampleQuality);
971 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
974 if(MultisampleQuality > 0) {
975 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
976 MultisampleQuality=0;
979 /** FIXME: Check that the format is supported
980 * by the device.
981 *******************************/
983 /* Non-power2 support */
984 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
985 pow2Width = Width;
986 pow2Height = Height;
987 } else {
988 /* Find the nearest pow2 match */
989 pow2Width = pow2Height = 1;
990 while (pow2Width < Width) pow2Width <<= 1;
991 while (pow2Height < Height) pow2Height <<= 1;
994 if (pow2Width > Width || pow2Height > Height) {
995 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
996 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
997 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
998 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
999 This, Width, Height);
1000 return WINED3DERR_NOTAVAILABLE;
1004 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1005 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1006 * space!
1007 *********************************/
1008 if (WINED3DFMT_UNKNOWN == Format) {
1009 Size = 0;
1010 } else if (Format == WINED3DFMT_DXT1) {
1011 /* DXT1 is half byte per pixel */
1012 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1014 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1015 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1016 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1017 } else {
1018 /* The pitch is a multiple of 4 bytes */
1019 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1020 Size *= pow2Height;
1023 /** Create and initialise the surface resource **/
1024 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1025 /* "Standalone" surface */
1026 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1028 object->currentDesc.Width = Width;
1029 object->currentDesc.Height = Height;
1030 object->currentDesc.MultiSampleType = MultiSample;
1031 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1033 /* Setup some glformat defaults */
1034 object->glDescription.glFormat = tableEntry->glFormat;
1035 object->glDescription.glFormatInternal = tableEntry->glInternal;
1036 object->glDescription.glType = tableEntry->glType;
1038 object->glDescription.textureName = 0;
1039 object->glDescription.level = Level;
1040 object->glDescription.target = GL_TEXTURE_2D;
1042 /* Internal data */
1043 object->pow2Width = pow2Width;
1044 object->pow2Height = pow2Height;
1046 /* Flags */
1047 object->Flags = 0; /* We start without flags set */
1048 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1049 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1050 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1051 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1054 if (WINED3DFMT_UNKNOWN != Format) {
1055 object->bytesPerPixel = tableEntry->bpp;
1056 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1057 object->pow2Size *= pow2Height;
1058 } else {
1059 object->bytesPerPixel = 0;
1060 object->pow2Size = 0;
1063 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1065 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1067 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1068 * this function is too deap to need to care about things like this.
1069 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1070 * ****************************************/
1071 switch(Pool) {
1072 case WINED3DPOOL_SCRATCH:
1073 if(!Lockable)
1074 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1075 which are mutually exclusive, setting lockable to true\n");
1076 Lockable = TRUE;
1077 break;
1078 case WINED3DPOOL_SYSTEMMEM:
1079 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1080 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1081 case WINED3DPOOL_MANAGED:
1082 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1083 Usage of DYNAMIC which are mutually exclusive, not doing \
1084 anything just telling you.\n");
1085 break;
1086 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1087 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1088 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1089 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1090 break;
1091 default:
1092 FIXME("(%p) Unknown pool %d\n", This, Pool);
1093 break;
1096 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1097 FIXME("Trying to create a render target that isn't in the default pool\n");
1100 /* mark the texture as dirty so that it get's loaded first time around*/
1101 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1102 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1103 This, Width, Height, Format, debug_d3dformat(Format),
1104 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1106 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1107 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1108 This->ddraw_primary = (IWineD3DSurface *) object;
1110 /* Look at the implementation and set the correct Vtable */
1111 switch(Impl) {
1112 case SURFACE_OPENGL:
1113 /* Nothing to do, it's set already */
1114 break;
1116 case SURFACE_GDI:
1117 object->lpVtbl = &IWineGDISurface_Vtbl;
1118 break;
1120 default:
1121 /* To be sure to catch this */
1122 ERR("Unknown requested surface implementation %d!\n", Impl);
1123 IWineD3DSurface_Release((IWineD3DSurface *) object);
1124 return WINED3DERR_INVALIDCALL;
1127 /* Call the private setup routine */
1128 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1132 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1133 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1134 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1135 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1138 IWineD3DTextureImpl *object;
1139 unsigned int i;
1140 UINT tmpW;
1141 UINT tmpH;
1142 HRESULT hr;
1143 unsigned int pow2Width;
1144 unsigned int pow2Height;
1147 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1148 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1149 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1151 /* TODO: It should only be possible to create textures for formats
1152 that are reported as supported */
1153 if (WINED3DFMT_UNKNOWN >= Format) {
1154 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1155 return WINED3DERR_INVALIDCALL;
1158 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1159 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1160 object->width = Width;
1161 object->height = Height;
1163 /** Non-power2 support **/
1164 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1165 pow2Width = Width;
1166 pow2Height = Height;
1167 } else {
1168 /* Find the nearest pow2 match */
1169 pow2Width = pow2Height = 1;
1170 while (pow2Width < Width) pow2Width <<= 1;
1171 while (pow2Height < Height) pow2Height <<= 1;
1174 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1175 /* Precalculated scaling for 'faked' non power of two texture coords */
1176 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1177 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1178 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1180 /* Calculate levels for mip mapping */
1181 if (Levels == 0) {
1182 TRACE("calculating levels %d\n", object->baseTexture.levels);
1183 object->baseTexture.levels++;
1184 tmpW = Width;
1185 tmpH = Height;
1186 while (tmpW > 1 || tmpH > 1) {
1187 tmpW = max(1, tmpW >> 1);
1188 tmpH = max(1, tmpH >> 1);
1189 object->baseTexture.levels++;
1191 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1194 /* Generate all the surfaces */
1195 tmpW = Width;
1196 tmpH = Height;
1197 for (i = 0; i < object->baseTexture.levels; i++)
1199 /* use the callback to create the texture surface */
1200 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1201 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1202 FIXME("Failed to create surface %p\n", object);
1203 /* clean up */
1204 object->surfaces[i] = NULL;
1205 IWineD3DTexture_Release((IWineD3DTexture *)object);
1207 *ppTexture = NULL;
1208 return hr;
1211 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1212 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1213 /* calculate the next mipmap level */
1214 tmpW = max(1, tmpW >> 1);
1215 tmpH = max(1, tmpH >> 1);
1218 TRACE("(%p) : Created texture %p\n", This, object);
1219 return WINED3D_OK;
1222 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1223 UINT Width, UINT Height, UINT Depth,
1224 UINT Levels, DWORD Usage,
1225 WINED3DFORMAT Format, WINED3DPOOL Pool,
1226 IWineD3DVolumeTexture **ppVolumeTexture,
1227 HANDLE *pSharedHandle, IUnknown *parent,
1228 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1231 IWineD3DVolumeTextureImpl *object;
1232 unsigned int i;
1233 UINT tmpW;
1234 UINT tmpH;
1235 UINT tmpD;
1237 /* TODO: It should only be possible to create textures for formats
1238 that are reported as supported */
1239 if (WINED3DFMT_UNKNOWN >= Format) {
1240 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1241 return WINED3DERR_INVALIDCALL;
1244 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1245 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1247 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1248 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1250 object->width = Width;
1251 object->height = Height;
1252 object->depth = Depth;
1254 /* Calculate levels for mip mapping */
1255 if (Levels == 0) {
1256 object->baseTexture.levels++;
1257 tmpW = Width;
1258 tmpH = Height;
1259 tmpD = Depth;
1260 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1261 tmpW = max(1, tmpW >> 1);
1262 tmpH = max(1, tmpH >> 1);
1263 tmpD = max(1, tmpD >> 1);
1264 object->baseTexture.levels++;
1266 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1269 /* Generate all the surfaces */
1270 tmpW = Width;
1271 tmpH = Height;
1272 tmpD = Depth;
1274 for (i = 0; i < object->baseTexture.levels; i++)
1276 /* Create the volume */
1277 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1278 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1280 /* Set it's container to this object */
1281 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1283 /* calcualte the next mipmap level */
1284 tmpW = max(1, tmpW >> 1);
1285 tmpH = max(1, tmpH >> 1);
1286 tmpD = max(1, tmpD >> 1);
1289 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1290 TRACE("(%p) : Created volume texture %p\n", This, object);
1291 return WINED3D_OK;
1294 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1295 UINT Width, UINT Height, UINT Depth,
1296 DWORD Usage,
1297 WINED3DFORMAT Format, WINED3DPOOL Pool,
1298 IWineD3DVolume** ppVolume,
1299 HANDLE* pSharedHandle, IUnknown *parent) {
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1303 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1305 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1307 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1308 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1310 object->currentDesc.Width = Width;
1311 object->currentDesc.Height = Height;
1312 object->currentDesc.Depth = Depth;
1313 object->bytesPerPixel = formatDesc->bpp;
1315 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1316 object->lockable = TRUE;
1317 object->locked = FALSE;
1318 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1319 object->dirty = TRUE;
1321 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1325 UINT Levels, DWORD Usage,
1326 WINED3DFORMAT Format, WINED3DPOOL Pool,
1327 IWineD3DCubeTexture **ppCubeTexture,
1328 HANDLE *pSharedHandle, IUnknown *parent,
1329 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1332 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1333 unsigned int i, j;
1334 UINT tmpW;
1335 HRESULT hr;
1336 unsigned int pow2EdgeLength = EdgeLength;
1338 /* TODO: It should only be possible to create textures for formats
1339 that are reported as supported */
1340 if (WINED3DFMT_UNKNOWN >= Format) {
1341 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1342 return WINED3DERR_INVALIDCALL;
1345 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1346 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1348 TRACE("(%p) Create Cube Texture\n", This);
1350 /** Non-power2 support **/
1352 /* Find the nearest pow2 match */
1353 pow2EdgeLength = 1;
1354 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1356 object->edgeLength = EdgeLength;
1357 /* TODO: support for native non-power 2 */
1358 /* Precalculated scaling for 'faked' non power of two texture coords */
1359 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1361 /* Calculate levels for mip mapping */
1362 if (Levels == 0) {
1363 object->baseTexture.levels++;
1364 tmpW = EdgeLength;
1365 while (tmpW > 1) {
1366 tmpW = max(1, tmpW >> 1);
1367 object->baseTexture.levels++;
1369 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1372 /* Generate all the surfaces */
1373 tmpW = EdgeLength;
1374 for (i = 0; i < object->baseTexture.levels; i++) {
1376 /* Create the 6 faces */
1377 for (j = 0; j < 6; j++) {
1379 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1380 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1382 if(hr!= WINED3D_OK) {
1383 /* clean up */
1384 int k;
1385 int l;
1386 for (l = 0; l < j; l++) {
1387 IWineD3DSurface_Release(object->surfaces[j][i]);
1389 for (k = 0; k < i; k++) {
1390 for (l = 0; l < 6; l++) {
1391 IWineD3DSurface_Release(object->surfaces[l][j]);
1395 FIXME("(%p) Failed to create surface\n",object);
1396 HeapFree(GetProcessHeap(),0,object);
1397 *ppCubeTexture = NULL;
1398 return hr;
1400 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1401 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1403 tmpW = max(1, tmpW >> 1);
1406 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1407 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1408 return WINED3D_OK;
1411 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1413 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1415 if (NULL == ppQuery) {
1416 /* Just a check to see if we support this type of query */
1417 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1418 switch(Type) {
1419 case WINED3DQUERYTYPE_OCCLUSION:
1420 TRACE("(%p) occlusion query\n", This);
1421 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1422 hr = WINED3D_OK;
1423 else
1424 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1425 break;
1426 case WINED3DQUERYTYPE_VCACHE:
1427 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1428 case WINED3DQUERYTYPE_VERTEXSTATS:
1429 case WINED3DQUERYTYPE_EVENT:
1430 case WINED3DQUERYTYPE_TIMESTAMP:
1431 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1432 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1433 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1434 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1435 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1436 case WINED3DQUERYTYPE_PIXELTIMINGS:
1437 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1438 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1439 default:
1440 FIXME("(%p) Unhandled query type %d\n", This, Type);
1442 return hr;
1445 D3DCREATEOBJECTINSTANCE(object, Query)
1446 object->type = Type;
1447 /* allocated the 'extended' data based on the type of query requested */
1448 switch(Type){
1449 case WINED3DQUERYTYPE_OCCLUSION:
1450 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1451 TRACE("(%p) Allocating data for an occlusion query\n", This);
1452 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1453 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1454 break;
1456 case WINED3DQUERYTYPE_VCACHE:
1457 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1458 case WINED3DQUERYTYPE_VERTEXSTATS:
1459 case WINED3DQUERYTYPE_EVENT:
1460 case WINED3DQUERYTYPE_TIMESTAMP:
1461 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1462 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1463 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1464 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1465 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1466 case WINED3DQUERYTYPE_PIXELTIMINGS:
1467 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1468 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1469 default:
1470 object->extendedData = 0;
1471 FIXME("(%p) Unhandled query type %d\n",This , Type);
1473 TRACE("(%p) : Created Query %p\n", This, object);
1474 return WINED3D_OK;
1477 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1478 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1479 IUnknown* parent,
1480 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1481 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1484 HDC hDc;
1485 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1486 int num;
1487 XVisualInfo template;
1488 GLXContext oldContext;
1489 Drawable oldDrawable;
1490 HRESULT hr = WINED3D_OK;
1492 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1494 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1495 * does a device hold a reference to a swap chain giving them a lifetime of the device
1496 * or does the swap chain notify the device of its destruction.
1497 *******************************/
1499 /* Check the params */
1500 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1501 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1502 return WINED3DERR_INVALIDCALL;
1503 } else if (*pPresentationParameters->BackBufferCount > 1) {
1504 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");
1507 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1509 /*********************
1510 * Lookup the window Handle and the relating X window handle
1511 ********************/
1513 /* Setup hwnd we are using, plus which display this equates to */
1514 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1515 if (!object->win_handle) {
1516 object->win_handle = This->createParms.hFocusWindow;
1519 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1520 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1521 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1522 return WINED3DERR_NOTAVAILABLE;
1524 hDc = GetDC(object->win_handle);
1525 object->display = get_display(hDc);
1526 ReleaseDC(object->win_handle, hDc);
1527 TRACE("Using a display of %p %p\n", object->display, hDc);
1529 if (NULL == object->display || NULL == hDc) {
1530 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1531 return WINED3DERR_NOTAVAILABLE;
1534 if (object->win == 0) {
1535 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1536 return WINED3DERR_NOTAVAILABLE;
1539 * Create an opengl context for the display visual
1540 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1541 * use different properties after that point in time. FIXME: How to handle when requested format
1542 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1543 * it chooses is identical to the one already being used!
1544 **********************************/
1546 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1547 ENTER_GL();
1549 /* Create a new context for this swapchain */
1550 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1551 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1552 (or the best possible if none is requested) */
1553 TRACE("Found x visual ID : %ld\n", template.visualid);
1555 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1556 if (NULL == object->visInfo) {
1557 ERR("cannot really get XVisual\n");
1558 LEAVE_GL();
1559 return WINED3DERR_NOTAVAILABLE;
1560 } else {
1561 int n, value;
1562 /* Write out some debug info about the visual/s */
1563 TRACE("Using x visual ID : %ld\n", template.visualid);
1564 TRACE(" visual info: %p\n", object->visInfo);
1565 TRACE(" num items : %d\n", num);
1566 for (n = 0;n < num; n++) {
1567 TRACE("=====item=====: %d\n", n + 1);
1568 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1569 TRACE(" screen : %d\n", object->visInfo[n].screen);
1570 TRACE(" depth : %u\n", object->visInfo[n].depth);
1571 TRACE(" class : %d\n", object->visInfo[n].class);
1572 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1573 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1574 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1575 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1576 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1577 /* log some extra glx info */
1578 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1579 TRACE(" gl_aux_buffers : %d\n", value);
1580 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1581 TRACE(" gl_buffer_size : %d\n", value);
1582 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1583 TRACE(" gl_red_size : %d\n", value);
1584 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1585 TRACE(" gl_green_size : %d\n", value);
1586 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1587 TRACE(" gl_blue_size : %d\n", value);
1588 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1589 TRACE(" gl_alpha_size : %d\n", value);
1590 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1591 TRACE(" gl_depth_size : %d\n", value);
1592 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1593 TRACE(" gl_stencil_size : %d\n", value);
1595 /* Now choose a simila visual ID*/
1597 #ifdef USE_CONTEXT_MANAGER
1599 /** TODO: use a context mamager **/
1600 #endif
1603 IWineD3DSwapChain *implSwapChain;
1604 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1605 /* The first time around we create the context that is shared with all other swapchains and render targets */
1606 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1607 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1608 } else {
1610 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1611 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1612 /* and create a new context with the implicit swapchains context as the shared context */
1613 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1614 IWineD3DSwapChain_Release(implSwapChain);
1618 /* Cleanup */
1619 XFree(object->visInfo);
1620 object->visInfo = NULL;
1622 LEAVE_GL();
1624 if (!object->glCtx) {
1625 ERR("Failed to create GLX context\n");
1626 return WINED3DERR_NOTAVAILABLE;
1627 } else {
1628 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1629 object->win_handle, object->glCtx, object->win, object->visInfo);
1632 /*********************
1633 * Windowed / Fullscreen
1634 *******************/
1637 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1638 * so we should really check to see if there is a fullscreen swapchain already
1639 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1640 **************************************/
1642 if (!*(pPresentationParameters->Windowed)) {
1644 DEVMODEW devmode;
1645 HDC hdc;
1646 int bpp = 0;
1648 /* Get info on the current display setup */
1649 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1650 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1651 DeleteDC(hdc);
1653 /* Change the display settings */
1654 memset(&devmode, 0, sizeof(DEVMODEW));
1655 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1656 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1657 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1658 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1659 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1660 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1662 /* Make popup window */
1663 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1664 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1665 *(pPresentationParameters->BackBufferWidth),
1666 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1668 /* For GetDisplayMode */
1669 This->ddraw_width = devmode.dmPelsWidth;
1670 This->ddraw_height = devmode.dmPelsHeight;
1671 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1675 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1676 * then the corresponding dimension of the client area of the hDeviceWindow
1677 * (or the focus window, if hDeviceWindow is NULL) is taken.
1678 **********************/
1680 if (*(pPresentationParameters->Windowed) &&
1681 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1682 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1684 RECT Rect;
1685 GetClientRect(object->win_handle, &Rect);
1687 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1688 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1689 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1691 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1692 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1693 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1697 /*********************
1698 * finish off parameter initialization
1699 *******************/
1701 /* Put the correct figures in the presentation parameters */
1702 TRACE("Coppying accross presentaion paraneters\n");
1703 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1704 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1705 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1706 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1707 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1708 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1709 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1710 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1711 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1712 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1713 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1714 object->presentParms.Flags = *(pPresentationParameters->Flags);
1715 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1716 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1719 /*********************
1720 * Create the back, front and stencil buffers
1721 *******************/
1723 TRACE("calling rendertarget CB\n");
1724 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1725 object->presentParms.BackBufferWidth,
1726 object->presentParms.BackBufferHeight,
1727 object->presentParms.BackBufferFormat,
1728 object->presentParms.MultiSampleType,
1729 object->presentParms.MultiSampleQuality,
1730 TRUE /* Lockable */,
1731 &object->frontBuffer,
1732 NULL /* pShared (always null)*/);
1733 if (object->frontBuffer != NULL)
1734 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1736 if(object->presentParms.BackBufferCount > 0) {
1737 int i;
1739 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1740 if(!object->backBuffer) {
1741 ERR("Out of memory\n");
1743 if (object->frontBuffer) {
1744 IUnknown *bufferParent;
1745 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1746 IUnknown_Release(bufferParent); /* once for the get parent */
1747 if (IUnknown_Release(bufferParent) > 0) {
1748 FIXME("(%p) Something's still holding the front buffer\n",This);
1751 HeapFree(GetProcessHeap(), 0, object);
1752 return E_OUTOFMEMORY;
1755 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1756 TRACE("calling rendertarget CB\n");
1757 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1758 object->presentParms.BackBufferWidth,
1759 object->presentParms.BackBufferHeight,
1760 object->presentParms.BackBufferFormat,
1761 object->presentParms.MultiSampleType,
1762 object->presentParms.MultiSampleQuality,
1763 TRUE /* Lockable */,
1764 &object->backBuffer[i],
1765 NULL /* pShared (always null)*/);
1766 if(hr == WINED3D_OK && object->backBuffer[i]) {
1767 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1768 } else {
1769 break;
1772 } else {
1773 object->backBuffer = NULL;
1776 if (object->backBuffer != NULL) {
1777 ENTER_GL();
1778 glDrawBuffer(GL_BACK);
1779 checkGLcall("glDrawBuffer(GL_BACK)");
1780 LEAVE_GL();
1781 } else {
1782 /* Single buffering - draw to front buffer */
1783 ENTER_GL();
1784 glDrawBuffer(GL_FRONT);
1785 checkGLcall("glDrawBuffer(GL_FRONT)");
1786 LEAVE_GL();
1789 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1790 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1791 TRACE("Creating depth stencil buffer\n");
1792 if (This->depthStencilBuffer == NULL ) {
1793 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1794 object->presentParms.BackBufferWidth,
1795 object->presentParms.BackBufferHeight,
1796 object->presentParms.AutoDepthStencilFormat,
1797 object->presentParms.MultiSampleType,
1798 object->presentParms.MultiSampleQuality,
1799 FALSE /* FIXME: Discard */,
1800 &This->depthStencilBuffer,
1801 NULL /* pShared (always null)*/ );
1802 if (This->depthStencilBuffer != NULL)
1803 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1806 /** TODO: A check on width, height and multisample types
1807 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1808 ****************************/
1809 object->wantsDepthStencilBuffer = TRUE;
1810 } else {
1811 object->wantsDepthStencilBuffer = FALSE;
1814 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1817 /*********************
1818 * init the default renderTarget management
1819 *******************/
1820 object->drawable = object->win;
1821 object->render_ctx = object->glCtx;
1823 if (hr == WINED3D_OK) {
1824 /*********************
1825 * Setup some defaults and clear down the buffers
1826 *******************/
1827 ENTER_GL();
1828 /** save current context and drawable **/
1829 oldContext = glXGetCurrentContext();
1830 oldDrawable = glXGetCurrentDrawable();
1832 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1833 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1834 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1836 checkGLcall("glXMakeCurrent");
1838 TRACE("Setting up the screen\n");
1839 /* Clear the screen */
1840 glClearColor(1.0, 0.0, 0.0, 0.0);
1841 checkGLcall("glClearColor");
1842 glClearIndex(0);
1843 glClearDepth(1);
1844 glClearStencil(0xffff);
1846 checkGLcall("glClear");
1848 glColor3f(1.0, 1.0, 1.0);
1849 checkGLcall("glColor3f");
1851 glEnable(GL_LIGHTING);
1852 checkGLcall("glEnable");
1854 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1855 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1857 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1858 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1860 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1861 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1863 /* switch back to the original context (if there was one)*/
1864 if (This->swapchains) {
1865 /** TODO: restore the context and drawable **/
1866 glXMakeCurrent(object->display, oldDrawable, oldContext);
1869 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1870 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1871 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1872 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1873 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1875 LEAVE_GL();
1877 TRACE("Set swapchain to %p\n", object);
1878 } else { /* something went wrong so clean up */
1879 IUnknown* bufferParent;
1880 if (object->frontBuffer) {
1882 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1883 IUnknown_Release(bufferParent); /* once for the get parent */
1884 if (IUnknown_Release(bufferParent) > 0) {
1885 FIXME("(%p) Something's still holding the front buffer\n",This);
1888 if (object->backBuffer) {
1889 int i;
1890 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1891 if(object->backBuffer[i]) {
1892 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1893 IUnknown_Release(bufferParent); /* once for the get parent */
1894 if (IUnknown_Release(bufferParent) > 0) {
1895 FIXME("(%p) Something's still holding the back buffer\n",This);
1899 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1900 object->backBuffer = NULL;
1902 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1903 /* Clean up the context */
1904 /* check that we are the current context first (we shouldn't be though!) */
1905 if (object->glCtx != 0) {
1906 if(glXGetCurrentContext() == object->glCtx) {
1907 glXMakeCurrent(object->display, None, NULL);
1909 glXDestroyContext(object->display, object->glCtx);
1911 HeapFree(GetProcessHeap(), 0, object);
1915 return hr;
1918 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1919 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1921 TRACE("(%p)\n", This);
1923 return This->NumberOfSwapChains;
1926 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1928 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1930 if(iSwapChain < This->NumberOfSwapChains) {
1931 *pSwapChain = This->swapchains[iSwapChain];
1932 IWineD3DSwapChain_AddRef(*pSwapChain);
1933 TRACE("(%p) returning %p\n", This, *pSwapChain);
1934 return WINED3D_OK;
1935 } else {
1936 TRACE("Swapchain out of range\n");
1937 *pSwapChain = NULL;
1938 return WINED3DERR_INVALIDCALL;
1942 /*****
1943 * Vertex Declaration
1944 *****/
1945 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1947 IWineD3DVertexDeclarationImpl *object = NULL;
1948 HRESULT hr = WINED3D_OK;
1949 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1950 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1951 object->allFVF = 0;
1953 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1955 return hr;
1958 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1961 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1962 HRESULT hr = WINED3D_OK;
1963 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1964 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1966 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1968 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1969 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1970 if (pDeclaration != NULL) {
1971 IWineD3DVertexDeclaration *vertexDeclaration;
1972 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1973 if (WINED3D_OK == hr) {
1974 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1975 object->vertexDeclaration = vertexDeclaration;
1976 } else {
1977 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1978 IWineD3DVertexShader_Release(*ppVertexShader);
1979 return WINED3DERR_INVALIDCALL;
1983 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1985 if (WINED3D_OK != hr) {
1986 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1987 IWineD3DVertexShader_Release(*ppVertexShader);
1988 return WINED3DERR_INVALIDCALL;
1991 #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. */
1992 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1993 /* Foo */
1994 } else {
1995 /* Bar */
1998 #endif
2000 return WINED3D_OK;
2003 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2005 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2006 HRESULT hr = WINED3D_OK;
2008 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2009 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2010 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2011 if (WINED3D_OK == hr) {
2012 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2013 } else {
2014 WARN("(%p) : Failed to create pixel shader\n", This);
2017 return hr;
2020 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2022 IWineD3DPaletteImpl *object;
2023 HRESULT hr;
2024 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2026 /* Create the new object */
2027 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2028 if(!object) {
2029 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2030 return E_OUTOFMEMORY;
2033 object->lpVtbl = &IWineD3DPalette_Vtbl;
2034 object->ref = 1;
2035 object->Flags = Flags;
2036 object->parent = Parent;
2037 object->wineD3DDevice = This;
2038 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2040 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2042 if(!object->hpal) {
2043 HeapFree( GetProcessHeap(), 0, object);
2044 return E_OUTOFMEMORY;
2047 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2048 if(FAILED(hr)) {
2049 IWineD3DPalette_Release((IWineD3DPalette *) object);
2050 return hr;
2053 *Palette = (IWineD3DPalette *) object;
2055 return WINED3D_OK;
2058 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2060 IWineD3DSwapChainImpl *swapchain;
2062 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2063 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2065 /* TODO: Test if OpenGL is compiled in and loaded */
2067 /* Setup the implicit swapchain */
2068 TRACE("Creating implicit swapchain\n");
2069 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2070 WARN("Failed to create implicit swapchain\n");
2071 return WINED3DERR_INVALIDCALL;
2074 This->NumberOfSwapChains = 1;
2075 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2076 if(!This->swapchains) {
2077 ERR("Out of memory!\n");
2078 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2079 return E_OUTOFMEMORY;
2081 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2083 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2084 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2085 This->renderTarget = swapchain->backBuffer[0];
2087 else {
2088 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2089 This->renderTarget = swapchain->frontBuffer;
2091 IWineD3DSurface_AddRef(This->renderTarget);
2092 /* Depth Stencil support */
2093 This->stencilBufferTarget = This->depthStencilBuffer;
2094 if (NULL != This->stencilBufferTarget) {
2095 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2098 /* Set up some starting GL setup */
2099 ENTER_GL();
2101 * Initialize openGL extension related variables
2102 * with Default values
2105 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2106 /* Setup all the devices defaults */
2107 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2108 #if 0
2109 IWineD3DImpl_CheckGraphicsMemory();
2110 #endif
2111 LEAVE_GL();
2113 /* Initialize our list of GLSL programs */
2114 list_init(&This->glsl_shader_progs);
2116 { /* Set a default viewport */
2117 WINED3DVIEWPORT vp;
2118 vp.X = 0;
2119 vp.Y = 0;
2120 vp.Width = *(pPresentationParameters->BackBufferWidth);
2121 vp.Height = *(pPresentationParameters->BackBufferHeight);
2122 vp.MinZ = 0.0f;
2123 vp.MaxZ = 1.0f;
2124 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2127 /* Initialize the current view state */
2128 This->modelview_valid = 1;
2129 This->proj_valid = 0;
2130 This->view_ident = 1;
2131 This->last_was_rhw = 0;
2132 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2133 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2135 /* Clear the screen */
2136 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2138 This->d3d_initialized = TRUE;
2139 return WINED3D_OK;
2142 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2144 int sampler;
2145 IUnknown* stencilBufferParent;
2146 IUnknown* swapChainParent;
2147 uint i;
2148 TRACE("(%p)\n", This);
2150 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2152 /* Delete the mouse cursor texture */
2153 if(This->cursorTexture) {
2154 ENTER_GL();
2155 glDeleteTextures(1, &This->cursorTexture);
2156 LEAVE_GL();
2157 This->cursorTexture = 0;
2160 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2161 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2164 /* Release the buffers (with sanity checks)*/
2165 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2166 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2167 if(This->depthStencilBuffer != This->stencilBufferTarget)
2168 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2170 This->stencilBufferTarget = NULL;
2172 TRACE("Releasing the render target at %p\n", This->renderTarget);
2173 if(IWineD3DSurface_Release(This->renderTarget) >0){
2174 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2176 TRACE("Setting rendertarget to NULL\n");
2177 This->renderTarget = NULL;
2179 if (This->depthStencilBuffer) {
2180 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2181 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2182 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2183 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2185 This->depthStencilBuffer = NULL;
2188 for(i=0; i < This->NumberOfSwapChains; i++) {
2189 TRACE("Releasing the implicit swapchain %d\n", i);
2190 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2191 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2192 IUnknown_Release(swapChainParent); /* once for the get parent */
2193 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2194 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2198 HeapFree(GetProcessHeap(), 0, This->swapchains);
2199 This->swapchains = NULL;
2200 This->NumberOfSwapChains = 0;
2202 This->d3d_initialized = FALSE;
2203 return WINED3D_OK;
2206 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2208 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2210 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2211 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2212 * DDraw doesn't necessarilly have a swapchain, so we have to store the fullscreen flag
2213 * seperately.
2215 This->ddraw_fullscreen = fullscreen;
2218 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2221 DEVMODEW DevModeW;
2222 int i;
2223 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2225 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2227 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2228 /* Ignore some modes if a description was passed */
2229 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2230 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2231 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2233 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2235 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2236 return D3D_OK;
2239 return D3D_OK;
2242 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2243 DEVMODEW devmode;
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 LONG ret;
2246 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2248 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2250 /* Resize the screen even without a window:
2251 * The app could have unset it with SetCooperativeLevel, but not called
2252 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2253 * but we don't have any hwnd
2256 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2257 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2258 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2259 devmode.dmPelsWidth = pMode->Width;
2260 devmode.dmPelsHeight = pMode->Height;
2262 devmode.dmDisplayFrequency = pMode->RefreshRate;
2263 if (pMode->RefreshRate != 0) {
2264 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2267 /* Only change the mode if necessary */
2268 if( (This->ddraw_width == pMode->Width) &&
2269 (This->ddraw_height == pMode->Height) &&
2270 (This->ddraw_format == pMode->Format) &&
2271 (pMode->RefreshRate == 0) ) {
2272 return D3D_OK;
2275 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2276 if (ret != DISP_CHANGE_SUCCESSFUL) {
2277 if(devmode.dmDisplayFrequency != 0) {
2278 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2279 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2280 devmode.dmDisplayFrequency = 0;
2281 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2283 if(ret != DISP_CHANGE_SUCCESSFUL) {
2284 return DDERR_INVALIDMODE;
2288 /* Store the new values */
2289 This->ddraw_width = pMode->Width;
2290 This->ddraw_height = pMode->Height;
2291 This->ddraw_format = pMode->Format;
2293 /* Only do this with a window of course */
2294 if(This->ddraw_window)
2295 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2297 return WINED3D_OK;
2300 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2302 *ppD3D= This->wineD3D;
2303 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2304 IWineD3D_AddRef(*ppD3D);
2305 return WINED3D_OK;
2308 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2309 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2310 * Into the video ram as possible and seeing how many fit
2311 * you can also get the correct initial value from nvidia and ATI's driver via X
2312 * texture memory is video memory + AGP memory
2313 *******************/
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 static BOOL showfixmes = TRUE;
2316 if (showfixmes) {
2317 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2318 (wined3d_settings.emulated_textureram/(1024*1024)),
2319 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2320 showfixmes = FALSE;
2322 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2323 (wined3d_settings.emulated_textureram/(1024*1024)),
2324 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2325 /* return simulated texture memory left */
2326 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2331 /*****
2332 * Get / Set FVF
2333 *****/
2334 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2336 HRESULT hr = WINED3D_OK;
2338 /* Update the current state block */
2339 This->updateStateBlock->fvf = fvf;
2340 This->updateStateBlock->changed.fvf = TRUE;
2341 This->updateStateBlock->set.fvf = TRUE;
2343 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2344 return hr;
2348 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2350 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2351 *pfvf = This->stateBlock->fvf;
2352 return WINED3D_OK;
2355 /*****
2356 * Get / Set Stream Source
2357 *****/
2358 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 IWineD3DVertexBuffer *oldSrc;
2362 /**TODO: instance and index data, see
2363 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2365 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2366 **************/
2368 /* D3d9 only, but shouldn't hurt d3d8 */
2369 UINT streamFlags;
2371 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2372 if (streamFlags) {
2373 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2374 FIXME("stream index data not supported\n");
2376 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2377 FIXME("stream instance data not supported\n");
2381 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2383 if (StreamNumber >= MAX_STREAMS) {
2384 WARN("Stream out of range %d\n", StreamNumber);
2385 return WINED3DERR_INVALIDCALL;
2388 oldSrc = This->stateBlock->streamSource[StreamNumber];
2389 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2391 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2392 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2393 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2394 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2395 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2396 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2398 /* Handle recording of state blocks */
2399 if (This->isRecordingState) {
2400 TRACE("Recording... not performing anything\n");
2401 return WINED3D_OK;
2404 /* Same stream object: no action */
2405 if (oldSrc == pStreamData)
2406 return WINED3D_OK;
2408 /* Need to do a getParent and pass the reffs up */
2409 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2410 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2411 so for now, just count internally */
2412 if (pStreamData != NULL) {
2413 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2414 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2415 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2417 vbImpl->stream = StreamNumber;
2418 vbImpl->Flags |= VBFLAG_STREAM;
2419 IWineD3DVertexBuffer_AddRef(pStreamData);
2421 if (oldSrc != NULL) {
2422 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2423 IWineD3DVertexBuffer_Release(oldSrc);
2426 return WINED3D_OK;
2429 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2431 UINT streamFlags;
2433 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2434 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2437 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2438 if (streamFlags) {
2439 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2440 FIXME("stream index data not supported\n");
2442 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2443 FIXME("stream instance data not supported\n");
2447 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2449 if (StreamNumber >= MAX_STREAMS) {
2450 WARN("Stream out of range %d\n", StreamNumber);
2451 return WINED3DERR_INVALIDCALL;
2453 *pStream = This->stateBlock->streamSource[StreamNumber];
2454 *pStride = This->stateBlock->streamStride[StreamNumber];
2455 if (pOffset) {
2456 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2459 if (*pStream == NULL) {
2460 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2461 return WINED3DERR_INVALIDCALL;
2464 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2465 return WINED3D_OK;
2468 /*Should be quite easy, just an extension of vertexdata
2469 ref...
2470 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2472 The divider is a bit odd though
2474 VertexOffset = StartVertex / Divider * StreamStride +
2475 VertexIndex / Divider * StreamStride + StreamOffset
2478 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2481 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2482 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2484 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2485 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2486 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2488 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2489 FIXME("Stream indexing not fully supported\n");
2492 return WINED3D_OK;
2495 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2498 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2499 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2501 TRACE("(%p) : returning %d\n", This, *Divider);
2503 return WINED3D_OK;
2506 /*****
2507 * Get / Set & Multiply Transform
2508 *****/
2509 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2512 /* Most of this routine, comments included copied from ddraw tree initially: */
2513 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2515 /* Handle recording of state blocks */
2516 if (This->isRecordingState) {
2517 TRACE("Recording... not performing anything\n");
2518 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2519 This->updateStateBlock->set.transform[d3dts] = TRUE;
2520 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2521 return WINED3D_OK;
2525 * If the new matrix is the same as the current one,
2526 * we cut off any further processing. this seems to be a reasonable
2527 * optimization because as was noticed, some apps (warcraft3 for example)
2528 * tend towards setting the same matrix repeatedly for some reason.
2530 * From here on we assume that the new matrix is different, wherever it matters.
2532 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2533 TRACE("The app is setting the same matrix over again\n");
2534 return WINED3D_OK;
2535 } else {
2536 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2540 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2541 where ViewMat = Camera space, WorldMat = world space.
2543 In OpenGL, camera and world space is combined into GL_MODELVIEW
2544 matrix. The Projection matrix stay projection matrix.
2547 /* Capture the times we can just ignore the change for now */
2548 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2549 This->modelview_valid = FALSE;
2550 return WINED3D_OK;
2552 } else if (d3dts == WINED3DTS_PROJECTION) {
2553 This->proj_valid = FALSE;
2554 return WINED3D_OK;
2556 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2557 /* Indexed Vertex Blending Matrices 256 -> 511 */
2558 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2559 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2560 return WINED3D_OK;
2563 /* Now we really are going to have to change a matrix */
2564 ENTER_GL();
2566 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2567 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2568 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2569 unsigned int k;
2571 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2572 * NOTE: We have to reset the positions even if the light/plane is not currently
2573 * enabled, since the call to enable it will not reset the position.
2574 * NOTE2: Apparently texture transforms do NOT need reapplying
2577 PLIGHTINFOEL *lightChain = NULL;
2578 This->modelview_valid = FALSE;
2579 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2581 glMatrixMode(GL_MODELVIEW);
2582 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2583 glPushMatrix();
2584 glLoadMatrixf((float *)lpmatrix);
2585 checkGLcall("glLoadMatrixf(...)");
2587 /* Reset lights */
2588 lightChain = This->stateBlock->lights;
2589 while (lightChain && lightChain->glIndex != -1) {
2590 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2591 checkGLcall("glLightfv posn");
2592 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2593 checkGLcall("glLightfv dirn");
2594 lightChain = lightChain->next;
2597 /* Reset Clipping Planes if clipping is enabled */
2598 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2599 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2600 checkGLcall("glClipPlane");
2602 glPopMatrix();
2604 } else { /* What was requested!?? */
2605 WARN("invalid matrix specified: %i\n", d3dts);
2608 /* Release lock, all done */
2609 LEAVE_GL();
2610 return WINED3D_OK;
2613 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2616 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2617 return WINED3D_OK;
2620 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2621 WINED3DMATRIX *mat = NULL;
2622 WINED3DMATRIX temp;
2624 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2625 * below means it will be recorded in a state block change, but it
2626 * works regardless where it is recorded.
2627 * If this is found to be wrong, change to StateBlock.
2629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2630 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2632 if (State < HIGHEST_TRANSFORMSTATE)
2634 mat = &This->updateStateBlock->transforms[State];
2635 } else {
2636 FIXME("Unhandled transform state!!\n");
2639 multiply_matrix(&temp, mat, (WINED3DMATRIX *) pMatrix);
2641 /* Apply change via set transform - will reapply to eg. lights this way */
2642 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2645 /*****
2646 * Get / Set Light
2647 *****/
2648 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2649 you can reference any indexes you want as long as that number max are enabled at any
2650 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2651 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2652 but when recording, just build a chain pretty much of commands to be replayed. */
2654 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2655 float rho;
2656 PLIGHTINFOEL *object, *temp;
2658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2661 /* If recording state block, just add to end of lights chain */
2662 if (This->isRecordingState) {
2663 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2664 if (NULL == object) {
2665 return WINED3DERR_OUTOFVIDEOMEMORY;
2667 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2668 object->OriginalIndex = Index;
2669 object->glIndex = -1;
2670 object->changed = TRUE;
2672 /* Add to the END of the chain of lights changes to be replayed */
2673 if (This->updateStateBlock->lights == NULL) {
2674 This->updateStateBlock->lights = object;
2675 } else {
2676 temp = This->updateStateBlock->lights;
2677 while (temp->next != NULL) temp=temp->next;
2678 temp->next = object;
2680 TRACE("Recording... not performing anything more\n");
2681 return WINED3D_OK;
2684 /* Ok, not recording any longer so do real work */
2685 object = This->stateBlock->lights;
2686 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2688 /* If we didn't find it in the list of lights, time to add it */
2689 if (object == NULL) {
2690 PLIGHTINFOEL *insertAt,*prevPos;
2692 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2693 if (NULL == object) {
2694 return WINED3DERR_OUTOFVIDEOMEMORY;
2696 object->OriginalIndex = Index;
2697 object->glIndex = -1;
2699 /* Add it to the front of list with the idea that lights will be changed as needed
2700 BUT after any lights currently assigned GL indexes */
2701 insertAt = This->stateBlock->lights;
2702 prevPos = NULL;
2703 while (insertAt != NULL && insertAt->glIndex != -1) {
2704 prevPos = insertAt;
2705 insertAt = insertAt->next;
2708 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2709 This->stateBlock->lights = object;
2710 } else if (insertAt == NULL) { /* End of list */
2711 prevPos->next = object;
2712 object->prev = prevPos;
2713 } else { /* Middle of chain */
2714 if (prevPos == NULL) {
2715 This->stateBlock->lights = object;
2716 } else {
2717 prevPos->next = object;
2719 object->prev = prevPos;
2720 object->next = insertAt;
2721 insertAt->prev = object;
2725 /* Initialize the object */
2726 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2727 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2728 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2729 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2730 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2731 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2732 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2734 /* Save away the information */
2735 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2737 switch (pLight->Type) {
2738 case WINED3DLIGHT_POINT:
2739 /* Position */
2740 object->lightPosn[0] = pLight->Position.x;
2741 object->lightPosn[1] = pLight->Position.y;
2742 object->lightPosn[2] = pLight->Position.z;
2743 object->lightPosn[3] = 1.0f;
2744 object->cutoff = 180.0f;
2745 /* FIXME: Range */
2746 break;
2748 case WINED3DLIGHT_DIRECTIONAL:
2749 /* Direction */
2750 object->lightPosn[0] = -pLight->Direction.x;
2751 object->lightPosn[1] = -pLight->Direction.y;
2752 object->lightPosn[2] = -pLight->Direction.z;
2753 object->lightPosn[3] = 0.0;
2754 object->exponent = 0.0f;
2755 object->cutoff = 180.0f;
2756 break;
2758 case WINED3DLIGHT_SPOT:
2759 /* Position */
2760 object->lightPosn[0] = pLight->Position.x;
2761 object->lightPosn[1] = pLight->Position.y;
2762 object->lightPosn[2] = pLight->Position.z;
2763 object->lightPosn[3] = 1.0;
2765 /* Direction */
2766 object->lightDirn[0] = pLight->Direction.x;
2767 object->lightDirn[1] = pLight->Direction.y;
2768 object->lightDirn[2] = pLight->Direction.z;
2769 object->lightDirn[3] = 1.0;
2772 * opengl-ish and d3d-ish spot lights use too different models for the
2773 * light "intensity" as a function of the angle towards the main light direction,
2774 * so we only can approximate very roughly.
2775 * however spot lights are rather rarely used in games (if ever used at all).
2776 * furthermore if still used, probably nobody pays attention to such details.
2778 if (pLight->Falloff == 0) {
2779 rho = 6.28f;
2780 } else {
2781 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2783 if (rho < 0.0001) rho = 0.0001f;
2784 object->exponent = -0.3/log(cos(rho/2));
2785 if (object->exponent > 128.0) {
2786 object->exponent = 128.0;
2788 object->cutoff = pLight->Phi*90/M_PI;
2790 /* FIXME: Range */
2791 break;
2793 default:
2794 FIXME("Unrecognized light type %d\n", pLight->Type);
2797 /* Update the live definitions if the light is currently assigned a glIndex */
2798 if (object->glIndex != -1) {
2799 setup_light(iface, object->glIndex, object);
2801 return WINED3D_OK;
2804 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2805 PLIGHTINFOEL *lightInfo = NULL;
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2809 /* Locate the light in the live lights */
2810 lightInfo = This->stateBlock->lights;
2811 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2813 if (lightInfo == NULL) {
2814 TRACE("Light information requested but light not defined\n");
2815 return WINED3DERR_INVALIDCALL;
2818 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2819 return WINED3D_OK;
2822 /*****
2823 * Get / Set Light Enable
2824 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2825 *****/
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2827 PLIGHTINFOEL *lightInfo = NULL;
2828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2829 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2831 /* Tests show true = 128...not clear why */
2833 Enable = Enable? 128: 0;
2835 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2836 if (This->isRecordingState) {
2837 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2838 if (NULL == lightInfo) {
2839 return WINED3DERR_OUTOFVIDEOMEMORY;
2841 lightInfo->OriginalIndex = Index;
2842 lightInfo->glIndex = -1;
2843 lightInfo->enabledChanged = TRUE;
2844 lightInfo->lightEnabled = Enable;
2846 /* Add to the END of the chain of lights changes to be replayed */
2847 if (This->updateStateBlock->lights == NULL) {
2848 This->updateStateBlock->lights = lightInfo;
2849 } else {
2850 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2851 while (temp->next != NULL) temp=temp->next;
2852 temp->next = lightInfo;
2854 TRACE("Recording... not performing anything more\n");
2855 return WINED3D_OK;
2858 /* Not recording... So, locate the light in the live lights */
2859 lightInfo = This->stateBlock->lights;
2860 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2862 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2863 if (lightInfo == NULL) {
2865 TRACE("Light enabled requested but light not defined, so defining one!\n");
2866 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2868 /* Search for it again! Should be fairly quick as near head of list */
2869 lightInfo = This->stateBlock->lights;
2870 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2871 if (lightInfo == NULL) {
2872 FIXME("Adding default lights has failed dismally\n");
2873 return WINED3DERR_INVALIDCALL;
2877 /* OK, we now have a light... */
2878 if (!Enable) {
2880 /* If we are disabling it, check it was enabled, and
2881 still only do something if it has assigned a glIndex (which it should have!) */
2882 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2883 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2884 ENTER_GL();
2885 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2886 checkGLcall("glDisable GL_LIGHT0+Index");
2887 LEAVE_GL();
2888 } else {
2889 TRACE("Nothing to do as light was not enabled\n");
2891 lightInfo->lightEnabled = Enable;
2892 } else {
2894 /* We are enabling it. If it is enabled, it's really simple */
2895 if (lightInfo->lightEnabled) {
2896 /* nop */
2897 TRACE("Nothing to do as light was enabled\n");
2899 /* If it already has a glIndex, it's still simple */
2900 } else if (lightInfo->glIndex != -1) {
2901 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2902 lightInfo->lightEnabled = Enable;
2903 ENTER_GL();
2904 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2905 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2906 LEAVE_GL();
2908 /* Otherwise got to find space - lights are ordered gl indexes first */
2909 } else {
2910 PLIGHTINFOEL *bsf = NULL;
2911 PLIGHTINFOEL *pos = This->stateBlock->lights;
2912 PLIGHTINFOEL *prev = NULL;
2913 int Index= 0;
2914 int glIndex = -1;
2916 /* Try to minimize changes as much as possible */
2917 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2919 /* Try to remember which index can be replaced if necessary */
2920 if (bsf==NULL && !pos->lightEnabled) {
2921 /* Found a light we can replace, save as best replacement */
2922 bsf = pos;
2925 /* Step to next space */
2926 prev = pos;
2927 pos = pos->next;
2928 Index ++;
2931 /* If we have too many active lights, fail the call */
2932 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2933 FIXME("Program requests too many concurrent lights\n");
2934 return WINED3DERR_INVALIDCALL;
2936 /* If we have allocated all lights, but not all are enabled,
2937 reuse one which is not enabled */
2938 } else if (Index == This->maxConcurrentLights) {
2939 /* use bsf - Simply swap the new light and the BSF one */
2940 PLIGHTINFOEL *bsfNext = bsf->next;
2941 PLIGHTINFOEL *bsfPrev = bsf->prev;
2943 /* Sort out ends */
2944 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2945 if (bsf->prev != NULL) {
2946 bsf->prev->next = lightInfo;
2947 } else {
2948 This->stateBlock->lights = lightInfo;
2951 /* If not side by side, lots of chains to update */
2952 if (bsf->next != lightInfo) {
2953 lightInfo->prev->next = bsf;
2954 bsf->next->prev = lightInfo;
2955 bsf->next = lightInfo->next;
2956 bsf->prev = lightInfo->prev;
2957 lightInfo->next = bsfNext;
2958 lightInfo->prev = bsfPrev;
2960 } else {
2961 /* Simple swaps */
2962 bsf->prev = lightInfo;
2963 bsf->next = lightInfo->next;
2964 lightInfo->next = bsf;
2965 lightInfo->prev = bsfPrev;
2969 /* Update states */
2970 glIndex = bsf->glIndex;
2971 bsf->glIndex = -1;
2972 lightInfo->glIndex = glIndex;
2973 lightInfo->lightEnabled = Enable;
2975 /* Finally set up the light in gl itself */
2976 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2977 ENTER_GL();
2978 setup_light(iface, glIndex, lightInfo);
2979 glEnable(GL_LIGHT0 + glIndex);
2980 checkGLcall("glEnable GL_LIGHT0 new setup");
2981 LEAVE_GL();
2983 /* If we reached the end of the allocated lights, with space in the
2984 gl lights, setup a new light */
2985 } else if (pos->glIndex == -1) {
2987 /* We reached the end of the allocated gl lights, so already
2988 know the index of the next one! */
2989 glIndex = Index;
2990 lightInfo->glIndex = glIndex;
2991 lightInfo->lightEnabled = Enable;
2993 /* In an ideal world, it's already in the right place */
2994 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2995 /* No need to move it */
2996 } else {
2997 /* Remove this light from the list */
2998 lightInfo->prev->next = lightInfo->next;
2999 if (lightInfo->next != NULL) {
3000 lightInfo->next->prev = lightInfo->prev;
3003 /* Add in at appropriate place (inbetween prev and pos) */
3004 lightInfo->prev = prev;
3005 lightInfo->next = pos;
3006 if (prev == NULL) {
3007 This->stateBlock->lights = lightInfo;
3008 } else {
3009 prev->next = lightInfo;
3011 if (pos != NULL) {
3012 pos->prev = lightInfo;
3016 /* Finally set up the light in gl itself */
3017 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3018 ENTER_GL();
3019 setup_light(iface, glIndex, lightInfo);
3020 glEnable(GL_LIGHT0 + glIndex);
3021 checkGLcall("glEnable GL_LIGHT0 new setup");
3022 LEAVE_GL();
3027 return WINED3D_OK;
3030 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3032 PLIGHTINFOEL *lightInfo = NULL;
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 TRACE("(%p) : for idx(%d)\n", This, Index);
3036 /* Locate the light in the live lights */
3037 lightInfo = This->stateBlock->lights;
3038 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3040 if (lightInfo == NULL) {
3041 TRACE("Light enabled state requested but light not defined\n");
3042 return WINED3DERR_INVALIDCALL;
3044 *pEnable = lightInfo->lightEnabled;
3045 return WINED3D_OK;
3048 /*****
3049 * Get / Set Clip Planes
3050 *****/
3051 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3055 /* Validate Index */
3056 if (Index >= GL_LIMITS(clipplanes)) {
3057 TRACE("Application has requested clipplane this device doesn't support\n");
3058 return WINED3DERR_INVALIDCALL;
3061 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3062 This->updateStateBlock->set.clipplane[Index] = TRUE;
3063 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3064 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3065 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3066 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3068 /* Handle recording of state blocks */
3069 if (This->isRecordingState) {
3070 TRACE("Recording... not performing anything\n");
3071 return WINED3D_OK;
3074 /* Apply it */
3076 ENTER_GL();
3078 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3079 glMatrixMode(GL_MODELVIEW);
3080 glPushMatrix();
3081 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3083 TRACE("Clipplane [%f,%f,%f,%f]\n",
3084 This->updateStateBlock->clipplane[Index][0],
3085 This->updateStateBlock->clipplane[Index][1],
3086 This->updateStateBlock->clipplane[Index][2],
3087 This->updateStateBlock->clipplane[Index][3]);
3088 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3089 checkGLcall("glClipPlane");
3091 glPopMatrix();
3092 LEAVE_GL();
3094 return WINED3D_OK;
3097 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3099 TRACE("(%p) : for idx %d\n", This, Index);
3101 /* Validate Index */
3102 if (Index >= GL_LIMITS(clipplanes)) {
3103 TRACE("Application has requested clipplane this device doesn't support\n");
3104 return WINED3DERR_INVALIDCALL;
3107 pPlane[0] = This->stateBlock->clipplane[Index][0];
3108 pPlane[1] = This->stateBlock->clipplane[Index][1];
3109 pPlane[2] = This->stateBlock->clipplane[Index][2];
3110 pPlane[3] = This->stateBlock->clipplane[Index][3];
3111 return WINED3D_OK;
3114 /*****
3115 * Get / Set Clip Plane Status
3116 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3117 *****/
3118 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 FIXME("(%p) : stub\n", This);
3121 if (NULL == pClipStatus) {
3122 return WINED3DERR_INVALIDCALL;
3124 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3125 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 FIXME("(%p) : stub\n", This);
3132 if (NULL == pClipStatus) {
3133 return WINED3DERR_INVALIDCALL;
3135 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3136 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3137 return WINED3D_OK;
3140 /*****
3141 * Get / Set Material
3142 *****/
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 This->updateStateBlock->changed.material = TRUE;
3147 This->updateStateBlock->set.material = TRUE;
3148 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3150 /* Handle recording of state blocks */
3151 if (This->isRecordingState) {
3152 TRACE("Recording... not performing anything\n");
3153 return WINED3D_OK;
3156 ENTER_GL();
3157 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3158 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3159 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3160 pMaterial->Ambient.b, pMaterial->Ambient.a);
3161 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3162 pMaterial->Specular.b, pMaterial->Specular.a);
3163 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3164 pMaterial->Emissive.b, pMaterial->Emissive.a);
3165 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3167 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3168 checkGLcall("glMaterialfv(GL_AMBIENT)");
3169 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3170 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3172 /* Only change material color if specular is enabled, otherwise it is set to black */
3173 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3174 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3175 checkGLcall("glMaterialfv(GL_SPECULAR");
3176 } else {
3177 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3178 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3179 checkGLcall("glMaterialfv(GL_SPECULAR");
3181 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3182 checkGLcall("glMaterialfv(GL_EMISSION)");
3183 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3184 checkGLcall("glMaterialf(GL_SHININESS");
3186 LEAVE_GL();
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3193 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3194 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3195 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3196 pMaterial->Ambient.b, pMaterial->Ambient.a);
3197 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3198 pMaterial->Specular.b, pMaterial->Specular.a);
3199 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3200 pMaterial->Emissive.b, pMaterial->Emissive.a);
3201 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3203 return WINED3D_OK;
3206 /*****
3207 * Get / Set Indices
3208 *****/
3209 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3210 UINT BaseVertexIndex) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 IWineD3DIndexBuffer *oldIdxs;
3214 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3215 oldIdxs = This->updateStateBlock->pIndexData;
3217 This->updateStateBlock->changed.indices = TRUE;
3218 This->updateStateBlock->set.indices = TRUE;
3219 This->updateStateBlock->pIndexData = pIndexData;
3220 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3222 /* Handle recording of state blocks */
3223 if (This->isRecordingState) {
3224 TRACE("Recording... not performing anything\n");
3225 return WINED3D_OK;
3228 if (NULL != pIndexData) {
3229 IWineD3DIndexBuffer_AddRef(pIndexData);
3231 if (NULL != oldIdxs) {
3232 IWineD3DIndexBuffer_Release(oldIdxs);
3234 return WINED3D_OK;
3237 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 *ppIndexData = This->stateBlock->pIndexData;
3242 /* up ref count on ppindexdata */
3243 if (*ppIndexData) {
3244 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3245 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3246 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3247 }else{
3248 TRACE("(%p) No index data set\n", This);
3250 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3252 return WINED3D_OK;
3255 /*****
3256 * Get / Set Viewports
3257 *****/
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 TRACE("(%p)\n", This);
3262 This->updateStateBlock->changed.viewport = TRUE;
3263 This->updateStateBlock->set.viewport = TRUE;
3264 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3266 /* Handle recording of state blocks */
3267 if (This->isRecordingState) {
3268 TRACE("Recording... not performing anything\n");
3269 return WINED3D_OK;
3271 This->viewport_changed = TRUE;
3273 ENTER_GL();
3275 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3276 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3278 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3279 checkGLcall("glDepthRange");
3280 /* Note: GL requires lower left, DirectX supplies upper left */
3281 /* TODO: replace usage of renderTarget with context management */
3282 glViewport(pViewport->X,
3283 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3284 pViewport->Width, pViewport->Height);
3286 checkGLcall("glViewport");
3288 LEAVE_GL();
3290 return WINED3D_OK;
3294 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 TRACE("(%p)\n", This);
3297 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3298 return WINED3D_OK;
3301 static void renderstate_stencil_twosided(
3302 IWineD3DDeviceImpl *This,
3303 GLint face,
3304 GLint func,
3305 GLint ref,
3306 GLuint mask,
3307 GLint stencilFail,
3308 GLint depthFail,
3309 GLint stencilPass ) {
3310 #if 0 /* Don't use OpenGL 2.0 calls for now */
3311 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3312 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3313 checkGLcall("glStencilFuncSeparate(...)");
3314 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3315 checkGLcall("glStencilOpSeparate(...)");
3317 else
3318 #endif
3319 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3320 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3321 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3322 GL_EXTCALL(glActiveStencilFaceEXT(face));
3323 checkGLcall("glActiveStencilFaceEXT(...)");
3324 glStencilFunc(func, ref, mask);
3325 checkGLcall("glStencilFunc(...)");
3326 glStencilOp(stencilFail, depthFail, stencilPass);
3327 checkGLcall("glStencilOp(...)");
3328 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3329 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3330 checkGLcall("glStencilFuncSeparateATI(...)");
3331 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3332 checkGLcall("glStencilOpSeparateATI(...)");
3333 } else {
3334 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3338 static void renderstate_stencil(IWineD3DDeviceImpl *This, WINED3DRENDERSTATETYPE State, DWORD Value) {
3339 DWORD onesided_enable = FALSE;
3340 DWORD twosided_enable = FALSE;
3341 GLint func = GL_ALWAYS;
3342 GLint func_ccw = GL_ALWAYS;
3343 GLint ref = 0;
3344 GLuint mask = 0;
3345 GLint stencilFail = GL_KEEP;
3346 GLint depthFail = GL_KEEP;
3347 GLint stencilPass = GL_KEEP;
3348 GLint stencilFail_ccw = GL_KEEP;
3349 GLint depthFail_ccw = GL_KEEP;
3350 GLint stencilPass_ccw = GL_KEEP;
3352 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3353 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3354 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3355 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3356 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3357 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3358 func = GL_ALWAYS;
3359 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3360 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3361 func = GL_ALWAYS;
3362 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3363 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3364 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3365 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3366 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3367 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3368 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3369 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3370 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3371 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3372 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3373 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3374 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3375 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3376 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3377 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3379 TRACE("(onesided %d, twosided %d, ref %x, mask %x, \
3380 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3381 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3382 onesided_enable, twosided_enable, ref, mask,
3383 func, stencilFail, depthFail, stencilPass,
3384 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3386 if (twosided_enable) {
3387 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3388 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3389 } else {
3390 if (onesided_enable) {
3391 glEnable(GL_STENCIL_TEST);
3392 checkGLcall("glEnable GL_STENCIL_TEST");
3393 glStencilFunc(func, ref, mask);
3394 checkGLcall("glStencilFunc(...)");
3395 glStencilOp(stencilFail, depthFail, stencilPass);
3396 checkGLcall("glStencilOp(...)");
3397 } else {
3398 glDisable(GL_STENCIL_TEST);
3399 checkGLcall("glDisable GL_STENCIL_TEST");
3404 /*****
3405 * Get / Set Render States
3406 * TODO: Verify against dx9 definitions
3407 *****/
3408 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 DWORD OldValue = This->stateBlock->renderState[State];
3413 /* Simple way of referring to either a DWORD or a 4 byte float */
3414 union {
3415 DWORD d;
3416 float f;
3417 } tmpvalue;
3419 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3420 This->updateStateBlock->changed.renderState[State] = TRUE;
3421 This->updateStateBlock->set.renderState[State] = TRUE;
3422 This->updateStateBlock->renderState[State] = Value;
3424 /* Handle recording of state blocks */
3425 if (This->isRecordingState) {
3426 TRACE("Recording... not performing anything\n");
3427 return WINED3D_OK;
3430 ENTER_GL();
3432 switch (State) {
3433 case WINED3DRS_FILLMODE :
3434 switch ((D3DFILLMODE) Value) {
3435 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3436 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3437 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3438 default:
3439 FIXME("Unrecognized WINED3DRS_FILLMODE value %d\n", Value);
3441 checkGLcall("glPolygonMode (fillmode)");
3442 break;
3444 case WINED3DRS_LIGHTING :
3445 if (Value) {
3446 glEnable(GL_LIGHTING);
3447 checkGLcall("glEnable GL_LIGHTING");
3448 } else {
3449 glDisable(GL_LIGHTING);
3450 checkGLcall("glDisable GL_LIGHTING");
3452 break;
3454 case WINED3DRS_ZENABLE :
3455 switch ((D3DZBUFFERTYPE) Value) {
3456 case D3DZB_FALSE:
3457 glDisable(GL_DEPTH_TEST);
3458 checkGLcall("glDisable GL_DEPTH_TEST");
3459 break;
3460 case D3DZB_TRUE:
3461 glEnable(GL_DEPTH_TEST);
3462 checkGLcall("glEnable GL_DEPTH_TEST");
3463 break;
3464 case D3DZB_USEW:
3465 glEnable(GL_DEPTH_TEST);
3466 checkGLcall("glEnable GL_DEPTH_TEST");
3467 FIXME("W buffer is not well handled\n");
3468 break;
3469 default:
3470 FIXME("Unrecognized D3DZBUFFERTYPE value %d\n", Value);
3472 break;
3474 case WINED3DRS_CULLMODE :
3476 /* If we are culling "back faces with clockwise vertices" then
3477 set front faces to be counter clockwise and enable culling
3478 of back faces */
3479 switch ((D3DCULL) Value) {
3480 case D3DCULL_NONE:
3481 glDisable(GL_CULL_FACE);
3482 checkGLcall("glDisable GL_CULL_FACE");
3483 break;
3484 case D3DCULL_CW:
3485 glEnable(GL_CULL_FACE);
3486 checkGLcall("glEnable GL_CULL_FACE");
3487 if (This->renderUpsideDown) {
3488 glFrontFace(GL_CW);
3489 checkGLcall("glFrontFace GL_CW");
3490 } else {
3491 glFrontFace(GL_CCW);
3492 checkGLcall("glFrontFace GL_CCW");
3494 glCullFace(GL_BACK);
3495 break;
3496 case D3DCULL_CCW:
3497 glEnable(GL_CULL_FACE);
3498 checkGLcall("glEnable GL_CULL_FACE");
3499 if (This->renderUpsideDown) {
3500 glFrontFace(GL_CCW);
3501 checkGLcall("glFrontFace GL_CCW");
3502 } else {
3503 glFrontFace(GL_CW);
3504 checkGLcall("glFrontFace GL_CW");
3506 glCullFace(GL_BACK);
3507 break;
3508 default:
3509 FIXME("Unrecognized/Unhandled D3DCULL value %d\n", Value);
3511 break;
3513 case WINED3DRS_SHADEMODE :
3514 switch ((D3DSHADEMODE) Value) {
3515 case D3DSHADE_FLAT:
3516 glShadeModel(GL_FLAT);
3517 checkGLcall("glShadeModel");
3518 break;
3519 case D3DSHADE_GOURAUD:
3520 glShadeModel(GL_SMOOTH);
3521 checkGLcall("glShadeModel");
3522 break;
3523 case D3DSHADE_PHONG:
3524 FIXME("D3DSHADE_PHONG isn't supported\n");
3525 break;
3526 default:
3527 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %d\n", Value);
3529 break;
3531 case WINED3DRS_DITHERENABLE :
3532 if (Value) {
3533 glEnable(GL_DITHER);
3534 checkGLcall("glEnable GL_DITHER");
3535 } else {
3536 glDisable(GL_DITHER);
3537 checkGLcall("glDisable GL_DITHER");
3539 break;
3541 case WINED3DRS_ZWRITEENABLE :
3542 if (Value) {
3543 glDepthMask(1);
3544 checkGLcall("glDepthMask");
3545 } else {
3546 glDepthMask(0);
3547 checkGLcall("glDepthMask");
3549 break;
3551 case WINED3DRS_ZFUNC :
3553 int glParm = CompareFunc(Value);
3555 if(glParm) {
3556 glDepthFunc(glParm);
3557 checkGLcall("glDepthFunc");
3560 break;
3562 case WINED3DRS_AMBIENT :
3564 float col[4];
3565 D3DCOLORTOGLFLOAT4(Value, col);
3566 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3567 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3568 checkGLcall("glLightModel for MODEL_AMBIENT");
3571 break;
3573 case WINED3DRS_ALPHABLENDENABLE :
3574 if (Value) {
3575 glEnable(GL_BLEND);
3576 checkGLcall("glEnable GL_BLEND");
3577 } else {
3578 glDisable(GL_BLEND);
3579 checkGLcall("glDisable GL_BLEND");
3581 break;
3583 case WINED3DRS_SRCBLEND :
3584 case WINED3DRS_DESTBLEND :
3586 int newVal = GL_ZERO;
3587 switch (Value) {
3588 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3589 case D3DBLEND_ONE : newVal = GL_ONE; break;
3590 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3591 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3592 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3593 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3594 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3595 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3596 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3597 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3598 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3600 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3601 This->srcBlend = newVal;
3602 This->dstBlend = newVal;
3603 break;
3605 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3606 This->srcBlend = newVal;
3607 This->dstBlend = newVal;
3608 break;
3609 case D3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3610 case D3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3611 default:
3612 FIXME("Unrecognized src/dest blend value %d (%d)\n", Value, State);
3615 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3616 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3617 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3618 glBlendFunc(This->srcBlend, This->dstBlend);
3620 checkGLcall("glBlendFunc");
3622 break;
3624 case WINED3DRS_ALPHATESTENABLE :
3625 case WINED3DRS_ALPHAFUNC :
3626 case WINED3DRS_ALPHAREF :
3627 case WINED3DRS_COLORKEYENABLE :
3629 int glParm = 0;
3630 float ref;
3631 BOOL enable_ckey = FALSE;
3633 IWineD3DSurfaceImpl *surf;
3635 /* Find out if the texture on the first stage has a ckey set */
3636 if(This->stateBlock->textures[0]) {
3637 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3638 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3641 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3642 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3643 glEnable(GL_ALPHA_TEST);
3644 checkGLcall("glEnable GL_ALPHA_TEST");
3645 } else {
3646 glDisable(GL_ALPHA_TEST);
3647 checkGLcall("glDisable GL_ALPHA_TEST");
3648 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3649 * enable call
3651 break;
3654 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3655 glParm = GL_NOTEQUAL;
3656 ref = 0.0;
3657 } else {
3658 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3659 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3661 if(glParm) {
3662 This->alphafunc = glParm;
3663 glAlphaFunc(glParm, ref);
3664 checkGLcall("glAlphaFunc");
3667 break;
3669 case WINED3DRS_CLIPPLANEENABLE :
3670 case WINED3DRS_CLIPPING :
3672 /* Ensure we only do the changed clip planes */
3673 DWORD enable = 0xFFFFFFFF;
3674 DWORD disable = 0x00000000;
3676 /* If enabling / disabling all */
3677 if (State == WINED3DRS_CLIPPING) {
3678 if (Value) {
3679 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3680 disable = 0x00;
3681 } else {
3682 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3683 enable = 0x00;
3685 } else {
3686 enable = Value & ~OldValue;
3687 disable = ~Value & OldValue;
3690 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3691 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3692 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3693 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3694 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3695 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3697 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3698 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3699 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3700 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3701 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3702 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3704 /** update clipping status */
3705 if (enable) {
3706 This->stateBlock->clip_status.ClipUnion = 0;
3707 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3708 } else {
3709 This->stateBlock->clip_status.ClipUnion = 0;
3710 This->stateBlock->clip_status.ClipIntersection = 0;
3713 break;
3715 case WINED3DRS_BLENDOP :
3717 int glParm = GL_FUNC_ADD;
3719 switch ((D3DBLENDOP) Value) {
3720 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3721 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3722 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3723 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3724 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3725 default:
3726 FIXME("Unrecognized/Unhandled D3DBLENDOP value %d\n", Value);
3729 if(GL_SUPPORT(EXT_BLEND_MINMAX)) {
3730 TRACE("glBlendEquation(%x)\n", glParm);
3731 GL_EXTCALL(glBlendEquation(glParm));
3732 checkGLcall("glBlendEquation");
3733 } else {
3734 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3737 break;
3739 case WINED3DRS_TEXTUREFACTOR :
3741 unsigned int i;
3743 /* Note the texture color applies to all textures whereas
3744 GL_TEXTURE_ENV_COLOR applies to active only */
3745 float col[4];
3746 D3DCOLORTOGLFLOAT4(Value, col);
3748 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3749 /* And now the default texture color as well */
3750 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3751 /* Note the WINED3DRS value applies to all textures, but GL has one
3752 per texture, so apply it now ready to be used! */
3753 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3754 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3755 checkGLcall("glActiveTextureARB");
3756 } else if (i>0) {
3757 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3760 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3761 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3765 break;
3767 case WINED3DRS_SPECULARENABLE :
3769 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3770 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3771 specular color. This is wrong:
3772 Separate specular color means the specular colour is maintained separately, whereas
3773 single color means it is merged in. However in both cases they are being used to
3774 some extent.
3775 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3776 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3777 running 1.4 yet!
3780 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3781 * Instead, we need to setup the FinalCombiner properly.
3783 * The default setup for the FinalCombiner is:
3785 * <variable> <input> <mapping> <usage>
3786 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3787 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3788 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3789 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3790 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3791 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3792 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3794 * That's pretty much fine as it is, except for variable B, which needs to take
3795 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3796 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3799 if (Value) {
3800 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3801 checkGLcall("glMaterialfv");
3802 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3803 glEnable(GL_COLOR_SUM_EXT);
3804 } else {
3805 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3807 checkGLcall("glEnable(GL_COLOR_SUM)");
3809 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3810 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3811 checkGLcall("glFinalCombinerInputNV()");
3813 } else {
3814 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3816 /* for the case of enabled lighting: */
3817 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3818 checkGLcall("glMaterialfv");
3820 /* for the case of disabled lighting: */
3821 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3822 glDisable(GL_COLOR_SUM_EXT);
3823 } else {
3824 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3826 checkGLcall("glDisable(GL_COLOR_SUM)");
3828 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3829 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3830 checkGLcall("glFinalCombinerInputNV()");
3834 break;
3836 case WINED3DRS_STENCILENABLE :
3837 case WINED3DRS_TWOSIDEDSTENCILMODE :
3838 case WINED3DRS_STENCILFUNC :
3839 case WINED3DRS_CCW_STENCILFUNC :
3840 case WINED3DRS_STENCILREF :
3841 case WINED3DRS_STENCILMASK :
3842 case WINED3DRS_STENCILFAIL :
3843 case WINED3DRS_STENCILZFAIL :
3844 case WINED3DRS_STENCILPASS :
3845 case WINED3DRS_CCW_STENCILFAIL :
3846 case WINED3DRS_CCW_STENCILZFAIL :
3847 case WINED3DRS_CCW_STENCILPASS :
3848 renderstate_stencil(This, State, Value);
3849 break;
3850 case WINED3DRS_STENCILWRITEMASK :
3852 glStencilMask(Value);
3853 TRACE("glStencilMask(%u)\n", Value);
3854 checkGLcall("glStencilMask");
3856 break;
3858 case WINED3DRS_FOGENABLE :
3860 if (Value) {
3861 glEnable(GL_FOG);
3862 checkGLcall("glEnable GL_FOG");
3863 } else {
3864 glDisable(GL_FOG);
3865 checkGLcall("glDisable GL_FOG");
3868 break;
3870 case WINED3DRS_RANGEFOGENABLE :
3872 if (Value) {
3873 TRACE("Enabled RANGEFOG\n");
3874 } else {
3875 TRACE("Disabled RANGEFOG\n");
3878 break;
3880 case WINED3DRS_FOGCOLOR :
3882 float col[4];
3883 D3DCOLORTOGLFLOAT4(Value, col);
3884 /* Set the default alpha blend color */
3885 glFogfv(GL_FOG_COLOR, &col[0]);
3886 checkGLcall("glFog GL_FOG_COLOR");
3888 break;
3890 case WINED3DRS_FOGTABLEMODE :
3891 case WINED3DRS_FOGVERTEXMODE :
3893 /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, the system will apply only pixel(=table) fog effects." */
3894 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3895 glHint(GL_FOG_HINT, GL_FASTEST);
3896 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3897 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3898 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3899 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3901 case D3DFOG_EXP: {
3902 if(!This->last_was_rhw) {
3903 glFogi(GL_FOG_MODE, GL_EXP);
3904 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3905 if(GL_SUPPORT(EXT_FOG_COORD)) {
3906 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3907 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3908 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3909 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3911 break;
3914 case D3DFOG_EXP2: {
3915 if(!This->last_was_rhw) {
3916 glFogi(GL_FOG_MODE, GL_EXP2);
3917 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3918 if(GL_SUPPORT(EXT_FOG_COORD)) {
3919 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3920 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3921 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3922 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3924 break;
3927 case D3DFOG_LINEAR: {
3928 if(!This->last_was_rhw) {
3929 glFogi(GL_FOG_MODE, GL_LINEAR);
3930 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3931 if(GL_SUPPORT(EXT_FOG_COORD)) {
3932 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3933 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3934 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3935 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3937 break;
3940 case D3DFOG_NONE: {
3941 /* Both are none? According to msdn the alpha channel of the specular
3942 * color contains a fog factor. Set it in drawStridedSlow.
3943 * Same happens with Vertexfog on transformed vertices
3945 if(GL_SUPPORT(EXT_FOG_COORD)) {
3946 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3947 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3948 glFogi(GL_FOG_MODE, GL_LINEAR);
3949 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3950 glFogf(GL_FOG_START, (float) 0xff);
3951 checkGLcall("glFogfv GL_FOG_START");
3952 glFogf(GL_FOG_END, 0.0);
3953 checkGLcall("glFogfv GL_FOG_END");
3954 } else {
3955 /* Disable GL fog, handle this in software in drawStridedSlow */
3956 glDisable(GL_FOG);
3957 checkGLcall("glDisable(GL_FOG)");
3959 break;
3961 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3963 } else {
3964 glHint(GL_FOG_HINT, GL_NICEST);
3965 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3966 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3967 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3968 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3969 if(GL_SUPPORT(EXT_FOG_COORD)) {
3970 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3971 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3972 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3973 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3975 break;
3976 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3977 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3978 if(GL_SUPPORT(EXT_FOG_COORD)) {
3979 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3980 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3981 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3982 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3984 break;
3985 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3986 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3987 if(GL_SUPPORT(EXT_FOG_COORD)) {
3988 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3989 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3990 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3991 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3993 break;
3994 case D3DFOG_NONE: /* Won't happen */
3995 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3998 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3999 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4002 break;
4004 case WINED3DRS_FOGSTART :
4006 tmpvalue.d = Value;
4007 glFogfv(GL_FOG_START, &tmpvalue.f);
4008 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4009 TRACE("Fog Start == %f\n", tmpvalue.f);
4011 break;
4013 case WINED3DRS_FOGEND :
4015 tmpvalue.d = Value;
4016 glFogfv(GL_FOG_END, &tmpvalue.f);
4017 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4018 TRACE("Fog End == %f\n", tmpvalue.f);
4020 break;
4022 case WINED3DRS_FOGDENSITY :
4024 tmpvalue.d = Value;
4025 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4026 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4028 break;
4030 case WINED3DRS_VERTEXBLEND :
4032 This->updateStateBlock->vertex_blend = (WINED3DVERTEXBLENDFLAGS) Value;
4033 TRACE("Vertex Blending state to %d\n", Value);
4035 break;
4037 case WINED3DRS_TWEENFACTOR :
4039 tmpvalue.d = Value;
4040 This->updateStateBlock->tween_factor = tmpvalue.f;
4041 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4043 break;
4045 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4047 TRACE("Indexed Vertex Blend Enable to %u\n", (BOOL) Value);
4049 break;
4051 case WINED3DRS_COLORVERTEX :
4052 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4053 case WINED3DRS_SPECULARMATERIALSOURCE :
4054 case WINED3DRS_AMBIENTMATERIALSOURCE :
4055 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4057 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4059 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4060 TRACE("diff %d, amb %d, emis %d, spec %d\n",
4061 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4062 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4063 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4064 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4066 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4067 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4068 Parm = GL_AMBIENT_AND_DIFFUSE;
4069 } else {
4070 Parm = GL_DIFFUSE;
4072 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4073 Parm = GL_AMBIENT;
4074 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4075 Parm = GL_EMISSION;
4076 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4077 Parm = GL_SPECULAR;
4078 } else {
4079 Parm = -1;
4082 if (Parm == -1) {
4083 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4084 } else {
4085 This->tracking_color = NEEDS_TRACKING;
4086 This->tracking_parm = Parm;
4089 } else {
4090 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4093 break;
4095 case WINED3DRS_LINEPATTERN :
4097 union {
4098 DWORD d;
4099 D3DLINEPATTERN lp;
4100 } tmppattern;
4101 tmppattern.d = Value;
4103 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4105 if (tmppattern.lp.wRepeatFactor) {
4106 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4107 checkGLcall("glLineStipple(repeat, linepattern)");
4108 glEnable(GL_LINE_STIPPLE);
4109 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4110 } else {
4111 glDisable(GL_LINE_STIPPLE);
4112 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4115 break;
4117 case WINED3DRS_ZBIAS : /* D3D8 only */
4119 if (Value) {
4120 tmpvalue.d = Value;
4121 TRACE("ZBias value %f\n", tmpvalue.f);
4122 glPolygonOffset(0, -tmpvalue.f);
4123 checkGLcall("glPolygonOffset(0, -Value)");
4124 glEnable(GL_POLYGON_OFFSET_FILL);
4125 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4126 glEnable(GL_POLYGON_OFFSET_LINE);
4127 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4128 glEnable(GL_POLYGON_OFFSET_POINT);
4129 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4130 } else {
4131 glDisable(GL_POLYGON_OFFSET_FILL);
4132 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4133 glDisable(GL_POLYGON_OFFSET_LINE);
4134 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4135 glDisable(GL_POLYGON_OFFSET_POINT);
4136 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4139 break;
4141 case WINED3DRS_NORMALIZENORMALS :
4142 if (Value) {
4143 glEnable(GL_NORMALIZE);
4144 checkGLcall("glEnable(GL_NORMALIZE);");
4145 } else {
4146 glDisable(GL_NORMALIZE);
4147 checkGLcall("glDisable(GL_NORMALIZE);");
4149 break;
4151 case WINED3DRS_POINTSIZE :
4152 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4153 tmpvalue.d = Value;
4154 TRACE("Set point size to %f\n", tmpvalue.f);
4155 glPointSize(tmpvalue.f);
4156 checkGLcall("glPointSize(...);");
4157 break;
4159 case WINED3DRS_POINTSIZE_MIN :
4160 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4161 tmpvalue.d = Value;
4162 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4163 checkGLcall("glPointParameterfEXT(...);");
4164 } else {
4165 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4167 break;
4169 case WINED3DRS_POINTSIZE_MAX :
4170 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4171 tmpvalue.d = Value;
4172 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4173 checkGLcall("glPointParameterfEXT(...);");
4174 } else {
4175 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4177 break;
4179 case WINED3DRS_POINTSCALE_A :
4180 case WINED3DRS_POINTSCALE_B :
4181 case WINED3DRS_POINTSCALE_C :
4182 case WINED3DRS_POINTSCALEENABLE :
4185 * POINTSCALEENABLE controls how point size value is treated. If set to
4186 * true, the point size is scaled with respect to height of viewport.
4187 * When set to false point size is in pixels.
4189 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4192 /* Default values */
4193 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4196 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4197 * This means that OpenGL will clamp really small point sizes to 1.0f.
4198 * To correct for this we need to multiply by the scale factor when sizes
4199 * are less than 1.0f. scale_factor = 1.0f / point_size.
4201 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4202 if(pointSize > 0.0f) {
4203 GLfloat scaleFactor;
4205 if(pointSize < 1.0f) {
4206 scaleFactor = pointSize * pointSize;
4207 } else {
4208 scaleFactor = 1.0f;
4211 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4212 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4213 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4214 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4215 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4216 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4217 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4221 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4222 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4223 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4225 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4226 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4227 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4228 } else {
4229 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4231 break;
4233 case WINED3DRS_COLORWRITEENABLE :
4235 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4236 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4237 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4238 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4239 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4240 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4241 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4242 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4243 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4244 checkGLcall("glColorMask(...)");
4246 break;
4248 case WINED3DRS_LOCALVIEWER :
4250 GLint state = (Value) ? 1 : 0;
4251 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4252 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4254 break;
4256 case WINED3DRS_LASTPIXEL :
4258 if (Value) {
4259 TRACE("Last Pixel Drawing Enabled\n");
4260 } else {
4261 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4264 break;
4266 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4268 if (Value) {
4269 TRACE("Software Processing Enabled\n");
4270 } else {
4271 TRACE("Software Processing Disabled\n");
4274 break;
4276 /** not supported */
4277 case WINED3DRS_ZVISIBLE :
4279 LEAVE_GL();
4280 return WINED3DERR_INVALIDCALL;
4282 case WINED3DRS_POINTSPRITEENABLE :
4284 /* TODO: NV_POINT_SPRITE */
4285 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4286 TRACE("Point sprites not supported\n");
4287 break;
4291 * Point sprites are always enabled. Value controls texture coordinate
4292 * replacement mode. Must be set true for point sprites to use
4293 * textures.
4295 glEnable(GL_POINT_SPRITE_ARB);
4296 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4298 if (Value) {
4299 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4300 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4301 } else {
4302 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4303 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4305 break;
4307 case WINED3DRS_EDGEANTIALIAS :
4309 if(Value) {
4310 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4311 glEnable(GL_BLEND);
4312 checkGLcall("glEnable(GL_BLEND)");
4313 glEnable(GL_LINE_SMOOTH);
4314 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4315 } else {
4316 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4317 glDisable(GL_BLEND);
4318 checkGLcall("glDisable(GL_BLEND)");
4320 glDisable(GL_LINE_SMOOTH);
4321 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4323 break;
4325 case WINED3DRS_WRAP0 :
4326 case WINED3DRS_WRAP1 :
4327 case WINED3DRS_WRAP2 :
4328 case WINED3DRS_WRAP3 :
4329 case WINED3DRS_WRAP4 :
4330 case WINED3DRS_WRAP5 :
4331 case WINED3DRS_WRAP6 :
4332 case WINED3DRS_WRAP7 :
4333 case WINED3DRS_WRAP8 :
4334 case WINED3DRS_WRAP9 :
4335 case WINED3DRS_WRAP10 :
4336 case WINED3DRS_WRAP11 :
4337 case WINED3DRS_WRAP12 :
4338 case WINED3DRS_WRAP13 :
4339 case WINED3DRS_WRAP14 :
4340 case WINED3DRS_WRAP15 :
4342 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4343 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4344 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4345 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4346 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4348 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4351 if(Value) {
4352 ERR("(%p)->(%s,%d) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4354 break;
4357 case WINED3DRS_MULTISAMPLEANTIALIAS :
4359 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4360 if(Value) {
4361 glEnable(GL_MULTISAMPLE_ARB);
4362 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4363 } else {
4364 glDisable(GL_MULTISAMPLE_ARB);
4365 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4367 } else {
4368 if(Value) {
4369 ERR("Multisample antialiasing not supported by gl\n");
4372 break;
4375 case WINED3DRS_SCISSORTESTENABLE :
4377 if(Value) {
4378 glEnable(GL_SCISSOR_TEST);
4379 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4380 } else {
4381 glDisable(GL_SCISSOR_TEST);
4382 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4384 break;
4386 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4388 if(Value) {
4389 tmpvalue.d = Value;
4390 glEnable(GL_POLYGON_OFFSET_FILL);
4391 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4392 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4393 checkGLcall("glPolygonOffset(...)");
4394 } else {
4395 glDisable(GL_POLYGON_OFFSET_FILL);
4396 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4398 break;
4400 case WINED3DRS_ANTIALIASEDLINEENABLE :
4402 if(Value) {
4403 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4404 glEnable(GL_BLEND);
4405 checkGLcall("glEnable(GL_BLEND)");
4406 glEnable(GL_LINE_SMOOTH);
4407 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4408 } else {
4409 glDisable(GL_BLEND);
4410 checkGLcall("glDisable(GL_BLEND)");
4411 glDisable(GL_LINE_SMOOTH);
4412 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4414 break;
4416 case WINED3DRS_DEPTHBIAS :
4418 if(Value) {
4419 tmpvalue.d = Value;
4420 glEnable(GL_POLYGON_OFFSET_FILL);
4421 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4422 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4423 checkGLcall("glPolygonOffset(...)");
4424 } else {
4425 glDisable(GL_POLYGON_OFFSET_FILL);
4426 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4428 break;
4431 case WINED3DRS_TEXTUREPERSPECTIVE :
4433 if (Value)
4434 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4435 else
4436 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4437 break;
4440 case WINED3DRS_STIPPLEDALPHA :
4442 if (Value)
4443 ERR(" Stippled Alpha not supported yet.\n");
4444 break;
4446 case WINED3DRS_ANTIALIAS :
4448 if (Value)
4449 ERR(" Antialias not supported yet.\n");
4450 break;
4453 case WINED3DRS_MULTISAMPLEMASK :
4455 if(0xFFFFFFFF != Value)
4456 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4457 break;
4460 case WINED3DRS_PATCHEDGESTYLE :
4462 if(D3DPATCHEDGE_DISCRETE != Value)
4463 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4464 break;
4467 case WINED3DRS_PATCHSEGMENTS :
4469 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4470 tmpvalue.f = 1.0f;
4471 if(tmpvalue.d != Value)
4472 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4473 break;
4476 case WINED3DRS_DEBUGMONITORTOKEN :
4478 /* Only useful for "debug builds". */
4479 if(0xbaadcafe != Value) {
4480 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4481 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4482 * but our tests disagree.
4483 * We do not claim to implement a debugging lib, so do not write an ERR
4485 WARN("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4487 break;
4490 case WINED3DRS_POSITIONDEGREE :
4492 if(D3DDEGREE_CUBIC != Value)
4493 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4494 break;
4497 case WINED3DRS_NORMALDEGREE :
4499 if(D3DDEGREE_LINEAR != Value)
4500 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4501 break;
4504 case WINED3DRS_MINTESSELLATIONLEVEL :
4505 case WINED3DRS_MAXTESSELLATIONLEVEL :
4506 case WINED3DRS_ADAPTIVETESS_X :
4507 case WINED3DRS_ADAPTIVETESS_Y :
4508 case WINED3DRS_ADAPTIVETESS_Z :
4509 case WINED3DRS_ADAPTIVETESS_W :
4511 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4512 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4513 else
4514 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4515 break;
4518 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4520 if(Value)
4521 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4522 break;
4525 case WINED3DRS_COLORWRITEENABLE1 :
4526 case WINED3DRS_COLORWRITEENABLE2 :
4527 case WINED3DRS_COLORWRITEENABLE3 :
4529 /* depends on WINED3DRS_COLORWRITEENABLE. */
4530 if(0x0000000F != Value)
4531 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4532 break;
4535 case WINED3DRS_BLENDFACTOR :
4537 float col[4];
4539 TRACE("Setting BlendFactor to %d\n", Value);
4541 D3DCOLORTOGLFLOAT4(Value, col);
4542 if (0xFFFFFFFF != Value) {
4543 glEnable(GL_BLEND);
4544 checkGLcall("glEnable(GL_BLEND)");
4546 else {
4547 glDisable(GL_BLEND);
4548 checkGLcall("glDisable(GL_BLEND)");
4550 glBlendColor (col[0],col[1],col[2],col[3]);
4551 break;
4554 case WINED3DRS_SRGBWRITEENABLE :
4556 if(Value)
4557 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4558 break;
4561 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4563 if(Value)
4564 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4565 break;
4568 case WINED3DRS_SRCBLENDALPHA :
4569 case WINED3DRS_DESTBLENDALPHA :
4570 case WINED3DRS_BLENDOPALPHA :
4572 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4573 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4574 else
4575 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4576 break;
4579 default:
4580 FIXME("(%p)->(%s,%d) unknown state\n", This, debug_d3drenderstate(State), Value);
4583 LEAVE_GL();
4585 return WINED3D_OK;
4588 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
4589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4590 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
4591 *pValue = This->stateBlock->renderState[State];
4592 return WINED3D_OK;
4595 /*****
4596 * Get / Set Sampler States
4597 * TODO: Verify against dx9 definitions
4598 *****/
4600 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 * SetSampler is designed to allow for more than the standard up to 8 textures
4604 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4605 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4607 * http://developer.nvidia.com/object/General_FAQ.html#t6
4609 * There are two new settings for GForce
4610 * the sampler one:
4611 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4612 * and the texture one:
4613 * GL_MAX_TEXTURE_COORDS_ARB.
4614 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4615 ******************/
4616 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4617 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4618 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4619 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4620 return WINED3DERR_INVALIDCALL;
4623 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
4624 debug_d3dsamplerstate(Type), Type, Value);
4625 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4626 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4627 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4629 /* Handle recording of state blocks */
4630 if (This->isRecordingState) {
4631 TRACE("Recording... not performing anything\n");
4632 return WINED3D_OK;
4635 return WINED3D_OK;
4638 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4640 /** TODO: check that sampler is in range **/
4641 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4642 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
4644 return WINED3D_OK;
4647 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 ENTER_GL();
4651 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4652 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4653 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4654 LEAVE_GL();
4656 return WINED3D_OK;
4659 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 GLint scissorBox[4];
4663 ENTER_GL();
4664 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4665 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4666 pRect->left = scissorBox[0];
4667 pRect->top = scissorBox[1];
4668 pRect->right = scissorBox[0] + scissorBox[2];
4669 pRect->bottom = scissorBox[1] + scissorBox[3];
4670 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4671 LEAVE_GL();
4672 return WINED3D_OK;
4675 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4677 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4679 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4681 This->updateStateBlock->vertexDecl = pDecl;
4682 This->updateStateBlock->changed.vertexDecl = TRUE;
4683 This->updateStateBlock->set.vertexDecl = TRUE;
4685 if (This->isRecordingState) {
4686 TRACE("Recording... not performing anything\n");
4689 if (NULL != pDecl) {
4690 IWineD3DVertexDeclaration_AddRef(pDecl);
4692 if (NULL != oldDecl) {
4693 IWineD3DVertexDeclaration_Release(oldDecl);
4695 return WINED3D_OK;
4698 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4701 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4703 *ppDecl = This->stateBlock->vertexDecl;
4704 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4705 return WINED3D_OK;
4708 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4710 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4712 This->updateStateBlock->vertexShader = pShader;
4713 This->updateStateBlock->changed.vertexShader = TRUE;
4714 This->updateStateBlock->set.vertexShader = TRUE;
4716 if (This->isRecordingState) {
4717 TRACE("Recording... not performing anything\n");
4720 if (NULL != pShader) {
4721 IWineD3DVertexShader_AddRef(pShader);
4723 if (NULL != oldShader) {
4724 IWineD3DVertexShader_Release(oldShader);
4727 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4729 * TODO: merge HAL shaders context switching from prototype
4731 return WINED3D_OK;
4734 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 if (NULL == ppShader) {
4738 return WINED3DERR_INVALIDCALL;
4740 *ppShader = This->stateBlock->vertexShader;
4741 if( NULL != *ppShader)
4742 IWineD3DVertexShader_AddRef(*ppShader);
4744 TRACE("(%p) : returning %p\n", This, *ppShader);
4745 return WINED3D_OK;
4748 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4749 IWineD3DDevice *iface,
4750 UINT start,
4751 CONST BOOL *srcData,
4752 UINT count) {
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4755 int i, cnt = min(count, MAX_CONST_B - start);
4757 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4758 iface, srcData, start, count);
4760 if (srcData == NULL || cnt < 0)
4761 return WINED3DERR_INVALIDCALL;
4763 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4764 for (i = 0; i < cnt; i++)
4765 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4767 for (i = start; i < cnt + start; ++i) {
4768 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4769 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4772 return WINED3D_OK;
4775 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4776 IWineD3DDevice *iface,
4777 UINT start,
4778 BOOL *dstData,
4779 UINT count) {
4781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 int cnt = min(count, MAX_CONST_B - start);
4784 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4785 iface, dstData, start, count);
4787 if (dstData == NULL || cnt < 0)
4788 return WINED3DERR_INVALIDCALL;
4790 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4791 return WINED3D_OK;
4794 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4795 IWineD3DDevice *iface,
4796 UINT start,
4797 CONST int *srcData,
4798 UINT count) {
4800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4801 int i, cnt = min(count, MAX_CONST_I - start);
4803 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4804 iface, srcData, start, count);
4806 if (srcData == NULL || cnt < 0)
4807 return WINED3DERR_INVALIDCALL;
4809 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4810 for (i = 0; i < cnt; i++)
4811 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4812 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4814 for (i = start; i < cnt + start; ++i) {
4815 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4816 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4819 return WINED3D_OK;
4822 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4823 IWineD3DDevice *iface,
4824 UINT start,
4825 int *dstData,
4826 UINT count) {
4828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4829 int cnt = min(count, MAX_CONST_I - start);
4831 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4832 iface, dstData, start, count);
4834 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4835 return WINED3DERR_INVALIDCALL;
4837 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4838 return WINED3D_OK;
4841 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4842 IWineD3DDevice *iface,
4843 UINT start,
4844 CONST float *srcData,
4845 UINT count) {
4847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4848 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4850 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4851 iface, srcData, start, count);
4853 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4854 return WINED3DERR_INVALIDCALL;
4856 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4857 for (i = 0; i < cnt; i++)
4858 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4859 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4861 for (i = start; i < cnt + start; ++i) {
4862 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4863 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4864 ptr->idx = i;
4865 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4866 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4868 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4871 return WINED3D_OK;
4874 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4875 IWineD3DDevice *iface,
4876 UINT start,
4877 float *dstData,
4878 UINT count) {
4880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4881 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4883 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4884 iface, dstData, start, count);
4886 if (dstData == NULL || cnt < 0)
4887 return WINED3DERR_INVALIDCALL;
4889 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4890 return WINED3D_OK;
4893 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4896 This->updateStateBlock->pixelShader = pShader;
4897 This->updateStateBlock->changed.pixelShader = TRUE;
4898 This->updateStateBlock->set.pixelShader = TRUE;
4900 /* Handle recording of state blocks */
4901 if (This->isRecordingState) {
4902 TRACE("Recording... not performing anything\n");
4905 if (NULL != pShader) {
4906 IWineD3DPixelShader_AddRef(pShader);
4908 if (NULL != oldShader) {
4909 IWineD3DPixelShader_Release(oldShader);
4912 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4914 * TODO: merge HAL shaders context switching from prototype
4916 return WINED3D_OK;
4919 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4922 if (NULL == ppShader) {
4923 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4924 return WINED3DERR_INVALIDCALL;
4927 *ppShader = This->stateBlock->pixelShader;
4928 if (NULL != *ppShader) {
4929 IWineD3DPixelShader_AddRef(*ppShader);
4931 TRACE("(%p) : returning %p\n", This, *ppShader);
4932 return WINED3D_OK;
4935 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4936 IWineD3DDevice *iface,
4937 UINT start,
4938 CONST BOOL *srcData,
4939 UINT count) {
4941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4942 int i, cnt = min(count, MAX_CONST_B - start);
4944 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4945 iface, srcData, start, count);
4947 if (srcData == NULL || cnt < 0)
4948 return WINED3DERR_INVALIDCALL;
4950 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4951 for (i = 0; i < cnt; i++)
4952 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4954 for (i = start; i < cnt + start; ++i) {
4955 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4956 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4959 return WINED3D_OK;
4962 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4963 IWineD3DDevice *iface,
4964 UINT start,
4965 BOOL *dstData,
4966 UINT count) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4969 int cnt = min(count, MAX_CONST_B - start);
4971 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4972 iface, dstData, start, count);
4974 if (dstData == NULL || cnt < 0)
4975 return WINED3DERR_INVALIDCALL;
4977 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4978 return WINED3D_OK;
4981 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4982 IWineD3DDevice *iface,
4983 UINT start,
4984 CONST int *srcData,
4985 UINT count) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4988 int i, cnt = min(count, MAX_CONST_I - start);
4990 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4991 iface, srcData, start, count);
4993 if (srcData == NULL || cnt < 0)
4994 return WINED3DERR_INVALIDCALL;
4996 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4997 for (i = 0; i < cnt; i++)
4998 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4999 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5001 for (i = start; i < cnt + start; ++i) {
5002 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
5003 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
5006 return WINED3D_OK;
5009 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
5010 IWineD3DDevice *iface,
5011 UINT start,
5012 int *dstData,
5013 UINT count) {
5015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5016 int cnt = min(count, MAX_CONST_I - start);
5018 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5019 iface, dstData, start, count);
5021 if (dstData == NULL || cnt < 0)
5022 return WINED3DERR_INVALIDCALL;
5024 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5025 return WINED3D_OK;
5028 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5029 IWineD3DDevice *iface,
5030 UINT start,
5031 CONST float *srcData,
5032 UINT count) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5035 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5037 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5038 iface, srcData, start, count);
5040 if (srcData == NULL || cnt < 0)
5041 return WINED3DERR_INVALIDCALL;
5043 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5044 for (i = 0; i < cnt; i++)
5045 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5046 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5048 for (i = start; i < cnt + start; ++i) {
5049 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5050 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5051 ptr->idx = i;
5052 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5053 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5055 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5058 return WINED3D_OK;
5061 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5062 IWineD3DDevice *iface,
5063 UINT start,
5064 float *dstData,
5065 UINT count) {
5067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5068 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5070 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5071 iface, dstData, start, count);
5073 if (dstData == NULL || cnt < 0)
5074 return WINED3DERR_INVALIDCALL;
5076 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5077 return WINED3D_OK;
5080 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5081 static HRESULT
5082 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5083 char *dest_ptr, *dest_conv = NULL;
5084 unsigned int i;
5085 DWORD DestFVF = dest->fvf;
5086 WINED3DVIEWPORT vp;
5087 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
5088 BOOL doClip;
5089 int numTextures;
5091 if (SrcFVF & D3DFVF_NORMAL) {
5092 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5095 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5096 ERR("Source has no position mask\n");
5097 return WINED3DERR_INVALIDCALL;
5100 /* We might access VBOs from this code, so hold the lock */
5101 ENTER_GL();
5103 if (dest->resource.allocatedMemory == NULL) {
5104 /* This may happen if we do direct locking into a vbo. Unlikely,
5105 * but theoretically possible(ddraw processvertices test)
5107 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5108 if(!dest->resource.allocatedMemory) {
5109 LEAVE_GL();
5110 ERR("Out of memory\n");
5111 return E_OUTOFMEMORY;
5113 if(dest->vbo) {
5114 void *src;
5115 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5116 checkGLcall("glBindBufferARB");
5117 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5118 if(src) {
5119 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5121 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5122 checkGLcall("glUnmapBufferARB");
5126 /* Get a pointer into the destination vbo(create one if none exists) and
5127 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5129 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5130 CreateVBO(dest);
5133 if(dest->vbo) {
5134 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5135 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5136 if(!dest_conv) {
5137 ERR("glMapBuffer failed\n");
5138 /* Continue without storing converted vertices */
5142 /* Should I clip?
5143 * a) WINED3DRS_CLIPPING is enabled
5144 * b) WINED3DVOP_CLIP is passed
5146 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5147 static BOOL warned = FALSE;
5149 * The clipping code is not quite correct. Some things need
5150 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5151 * so disable clipping for now.
5152 * (The graphics in Half-Life are broken, and my processvertices
5153 * test crashes with IDirect3DDevice3)
5154 doClip = TRUE;
5156 doClip = FALSE;
5157 if(!warned) {
5158 warned = TRUE;
5159 FIXME("Clipping is broken and disabled for now\n");
5161 } else doClip = FALSE;
5162 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5163 if(dest_conv) {
5164 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5167 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5168 WINED3DTS_VIEW,
5169 &view_mat);
5170 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5171 WINED3DTS_PROJECTION,
5172 &proj_mat);
5173 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5174 WINED3DTS_WORLDMATRIX(0),
5175 &world_mat);
5177 TRACE("View mat:\n");
5178 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); \
5179 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); \
5180 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); \
5181 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); \
5183 TRACE("Proj mat:\n");
5184 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); \
5185 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); \
5186 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); \
5187 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); \
5189 TRACE("World mat:\n");
5190 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); \
5191 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); \
5192 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); \
5193 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); \
5195 /* Get the viewport */
5196 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5197 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
5198 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5200 multiply_matrix(&mat,&view_mat,&world_mat);
5201 multiply_matrix(&mat,&proj_mat,&mat);
5203 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5205 for (i = 0; i < dwCount; i+= 1) {
5206 unsigned int tex_index;
5208 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5209 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5210 /* The position first */
5211 float *p =
5212 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5213 float x, y, z, rhw;
5214 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5216 /* Multiplication with world, view and projection matrix */
5217 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);
5218 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);
5219 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);
5220 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);
5222 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5224 /* WARNING: The following things are taken from d3d7 and were not yet checked
5225 * against d3d8 or d3d9!
5228 /* Clipping conditions: From
5229 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5231 * A vertex is clipped if it does not match the following requirements
5232 * -rhw < x <= rhw
5233 * -rhw < y <= rhw
5234 * 0 < z <= rhw
5235 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5237 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5238 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5242 if( !doClip ||
5243 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5244 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5245 ( rhw > eps ) ) ) {
5247 /* "Normal" viewport transformation (not clipped)
5248 * 1) The values are divided by rhw
5249 * 2) The y axis is negative, so multiply it with -1
5250 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5251 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5252 * 4) Multiply x with Width/2 and add Width/2
5253 * 5) The same for the height
5254 * 6) Add the viewpoint X and Y to the 2D coordinates and
5255 * The minimum Z value to z
5256 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5258 * Well, basically it's simply a linear transformation into viewport
5259 * coordinates
5262 x /= rhw;
5263 y /= rhw;
5264 z /= rhw;
5266 y *= -1;
5268 x *= vp.Width / 2;
5269 y *= vp.Height / 2;
5270 z *= vp.MaxZ - vp.MinZ;
5272 x += vp.Width / 2 + vp.X;
5273 y += vp.Height / 2 + vp.Y;
5274 z += vp.MinZ;
5276 rhw = 1 / rhw;
5277 } else {
5278 /* That vertex got clipped
5279 * Contrary to OpenGL it is not dropped completely, it just
5280 * undergoes a different calculation.
5282 TRACE("Vertex got clipped\n");
5283 x += rhw;
5284 y += rhw;
5286 x /= 2;
5287 y /= 2;
5289 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5290 * outside of the main vertex buffer memory. That needs some more
5291 * investigation...
5295 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5298 ( (float *) dest_ptr)[0] = x;
5299 ( (float *) dest_ptr)[1] = y;
5300 ( (float *) dest_ptr)[2] = z;
5301 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5303 dest_ptr += 3 * sizeof(float);
5305 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5306 dest_ptr += sizeof(float);
5309 if(dest_conv) {
5310 float w = 1 / rhw;
5311 ( (float *) dest_conv)[0] = x * w;
5312 ( (float *) dest_conv)[1] = y * w;
5313 ( (float *) dest_conv)[2] = z * w;
5314 ( (float *) dest_conv)[3] = w;
5316 dest_conv += 3 * sizeof(float);
5318 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5319 dest_conv += sizeof(float);
5323 if (DestFVF & D3DFVF_PSIZE) {
5324 dest_ptr += sizeof(DWORD);
5325 if(dest_conv) dest_conv += sizeof(DWORD);
5327 if (DestFVF & D3DFVF_NORMAL) {
5328 float *normal =
5329 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5330 /* AFAIK this should go into the lighting information */
5331 FIXME("Didn't expect the destination to have a normal\n");
5332 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5333 if(dest_conv) {
5334 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5338 if (DestFVF & D3DFVF_DIFFUSE) {
5339 DWORD *color_d =
5340 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5341 if(!color_d) {
5342 static BOOL warned = FALSE;
5344 if(!warned) {
5345 ERR("No diffuse color in source, but destination has one\n");
5346 warned = TRUE;
5349 *( (DWORD *) dest_ptr) = 0xffffffff;
5350 dest_ptr += sizeof(DWORD);
5352 if(dest_conv) {
5353 *( (DWORD *) dest_conv) = 0xffffffff;
5354 dest_conv += sizeof(DWORD);
5357 else {
5358 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5359 if(dest_conv) {
5360 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5361 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5362 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5363 dest_conv += sizeof(DWORD);
5368 if (DestFVF & D3DFVF_SPECULAR) {
5369 /* What's the color value in the feedback buffer? */
5370 DWORD *color_s =
5371 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5372 if(!color_s) {
5373 static BOOL warned = FALSE;
5375 if(!warned) {
5376 ERR("No specular color in source, but destination has one\n");
5377 warned = TRUE;
5380 *( (DWORD *) dest_ptr) = 0xFF000000;
5381 dest_ptr += sizeof(DWORD);
5383 if(dest_conv) {
5384 *( (DWORD *) dest_conv) = 0xFF000000;
5385 dest_conv += sizeof(DWORD);
5388 else {
5389 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5390 if(dest_conv) {
5391 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5392 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5393 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5394 dest_conv += sizeof(DWORD);
5399 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5400 float *tex_coord =
5401 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5402 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5403 if(!tex_coord) {
5404 ERR("No source texture, but destination requests one\n");
5405 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5406 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5408 else {
5409 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5410 if(dest_conv) {
5411 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5417 if(dest_conv) {
5418 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5419 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5422 LEAVE_GL();
5424 return WINED3D_OK;
5426 #undef copy_and_next
5428 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5430 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5431 WineDirect3DVertexStridedData strided;
5432 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5434 if (!SrcImpl) {
5435 WARN("NULL source vertex buffer\n");
5436 return WINED3DERR_INVALIDCALL;
5438 /* We don't need the source vbo because this buffer is only used as
5439 * a source for ProcessVertices. Avoid wasting resources by converting the
5440 * buffer and loading the VBO
5442 if(SrcImpl->vbo) {
5443 TRACE("Releaseing the source vbo, it won't be needed\n");
5445 if(!SrcImpl->resource.allocatedMemory) {
5446 /* Rescue the data from the buffer */
5447 void *src;
5448 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5449 if(!SrcImpl->resource.allocatedMemory) {
5450 ERR("Out of memory\n");
5451 return E_OUTOFMEMORY;
5454 ENTER_GL();
5455 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5456 checkGLcall("glBindBufferARB");
5458 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5459 if(src) {
5460 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5463 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5464 checkGLcall("glUnmapBufferARB");
5465 } else {
5466 ENTER_GL();
5469 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5470 checkGLcall("glBindBufferARB");
5471 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5472 checkGLcall("glDeleteBuffersARB");
5473 LEAVE_GL();
5475 SrcImpl->vbo = 0;
5478 memset(&strided, 0, sizeof(strided));
5479 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5481 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5484 /*****
5485 * Apply / Get / Set Texture Stage States
5486 * TODO: Verify against dx9 definitions
5487 *****/
5489 /* 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 */
5490 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5492 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5493 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5495 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5497 /* Check that the stage is within limits */
5498 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5499 TRACE("Attempt to access invalid texture rejected\n");
5500 return;
5503 ENTER_GL();
5505 switch (Type) {
5506 case WINED3DTSS_ALPHAOP :
5507 case WINED3DTSS_COLOROP :
5508 /* nothing to do as moved to drawprim for now */
5509 break;
5510 case WINED3DTSS_ADDRESSW :
5511 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5512 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5513 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %d, state %d\n", Value, Type);
5515 } else {
5516 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5517 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5518 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5519 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5521 #endif
5522 case WINED3DTSS_TEXCOORDINDEX :
5524 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5526 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5527 one flag, you can still specify an index value, which the system uses to
5528 determine the texture wrapping mode.
5529 eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5530 means use the vertex position (camera-space) as the input texture coordinates
5531 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5532 state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
5533 to the TEXCOORDINDEX value */
5536 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5538 switch (Value & 0xFFFF0000) {
5539 case D3DTSS_TCI_PASSTHRU:
5540 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5541 glDisable(GL_TEXTURE_GEN_S);
5542 glDisable(GL_TEXTURE_GEN_T);
5543 glDisable(GL_TEXTURE_GEN_R);
5544 glDisable(GL_TEXTURE_GEN_Q);
5545 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5546 break;
5548 case D3DTSS_TCI_CAMERASPACEPOSITION:
5549 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5550 as the input texture coordinates for this stage's texture transformation. This
5551 equates roughly to EYE_LINEAR */
5553 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5554 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5555 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5556 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5557 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5559 glMatrixMode(GL_MODELVIEW);
5560 glPushMatrix();
5561 glLoadIdentity();
5562 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5563 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5564 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5565 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5566 glPopMatrix();
5568 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5569 glEnable(GL_TEXTURE_GEN_S);
5570 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5571 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5572 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5573 glEnable(GL_TEXTURE_GEN_T);
5574 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5575 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5576 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5577 glEnable(GL_TEXTURE_GEN_R);
5578 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5579 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5580 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5582 break;
5584 case D3DTSS_TCI_CAMERASPACENORMAL:
5586 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5587 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5588 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5589 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5590 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5591 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5593 glMatrixMode(GL_MODELVIEW);
5594 glPushMatrix();
5595 glLoadIdentity();
5596 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5597 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5598 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5599 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5600 glPopMatrix();
5602 glEnable(GL_TEXTURE_GEN_S);
5603 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5604 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5605 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5606 glEnable(GL_TEXTURE_GEN_T);
5607 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5608 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5609 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5610 glEnable(GL_TEXTURE_GEN_R);
5611 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5612 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5613 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5616 break;
5618 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5620 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5621 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5622 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5623 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5624 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5625 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5627 glMatrixMode(GL_MODELVIEW);
5628 glPushMatrix();
5629 glLoadIdentity();
5630 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5631 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5632 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5633 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5634 glPopMatrix();
5636 glEnable(GL_TEXTURE_GEN_S);
5637 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5638 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5639 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5640 glEnable(GL_TEXTURE_GEN_T);
5641 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5642 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5643 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5644 glEnable(GL_TEXTURE_GEN_R);
5645 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5646 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5647 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5650 break;
5652 /* Unhandled types: */
5653 default:
5654 /* Todo: */
5655 /* ? disable GL_TEXTURE_GEN_n ? */
5656 glDisable(GL_TEXTURE_GEN_S);
5657 glDisable(GL_TEXTURE_GEN_T);
5658 glDisable(GL_TEXTURE_GEN_R);
5659 glDisable(GL_TEXTURE_GEN_Q);
5660 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
5661 break;
5664 break;
5666 /* Unhandled */
5667 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5668 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);
5669 break;
5671 case WINED3DTSS_BUMPENVMAT00 :
5672 case WINED3DTSS_BUMPENVMAT01 :
5673 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5674 break;
5675 case WINED3DTSS_BUMPENVMAT10 :
5676 case WINED3DTSS_BUMPENVMAT11 :
5677 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5678 break;
5680 case WINED3DTSS_BUMPENVLSCALE :
5681 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5682 break;
5684 case WINED3DTSS_BUMPENVLOFFSET :
5685 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5686 break;
5688 case WINED3DTSS_RESULTARG :
5689 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5690 break;
5692 default:
5693 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
5694 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5697 LEAVE_GL();
5699 return;
5702 /*****
5703 * Get / Set Texture Stage States
5704 * TODO: Verify against dx9 definitions
5705 *****/
5706 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5709 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5711 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5713 /* Reject invalid texture units */
5714 if (Stage >= GL_LIMITS(texture_stages)) {
5715 TRACE("Attempt to access invalid texture rejected\n");
5716 return WINED3DERR_INVALIDCALL;
5719 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5720 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5721 This->updateStateBlock->textureState[Stage][Type] = Value;
5723 return WINED3D_OK;
5726 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5729 *pValue = This->updateStateBlock->textureState[Stage][Type];
5730 return WINED3D_OK;
5733 /*****
5734 * Get / Set Texture
5735 *****/
5736 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 IWineD3DBaseTexture *oldTexture;
5741 oldTexture = This->updateStateBlock->textures[Stage];
5742 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
5744 #if 0 /* TODO: check so vertex textures */
5745 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5746 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5747 return WINED3D_OK;
5749 #endif
5751 /* Reject invalid texture units */
5752 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5753 WARN("Attempt to access invalid texture rejected\n");
5754 return WINED3DERR_INVALIDCALL;
5757 if(pTexture != NULL) {
5758 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5760 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5761 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5762 return WINED3DERR_INVALIDCALL;
5766 oldTexture = This->updateStateBlock->textures[Stage];
5767 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5768 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5770 This->updateStateBlock->set.textures[Stage] = TRUE;
5771 This->updateStateBlock->changed.textures[Stage] = TRUE;
5772 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5773 This->updateStateBlock->textures[Stage] = pTexture;
5775 /* Handle recording of state blocks */
5776 if (This->isRecordingState) {
5777 TRACE("Recording... not performing anything\n");
5778 return WINED3D_OK;
5781 /** NOTE: MSDN says that setTexture increases the reference count,
5782 * and the the application nust set the texture back to null (or have a leaky application),
5783 * This means we should pass the refcount up to the parent
5784 *******************************/
5785 if (NULL != This->updateStateBlock->textures[Stage]) {
5786 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5789 if (NULL != oldTexture) {
5790 IWineD3DBaseTexture_Release(oldTexture);
5793 /* Reset color keying */
5794 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5795 BOOL enable_ckey = FALSE;
5797 if(pTexture) {
5798 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5799 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5802 if(enable_ckey) {
5803 glAlphaFunc(GL_NOTEQUAL, 0.0);
5804 checkGLcall("glAlphaFunc");
5808 return WINED3D_OK;
5811 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5813 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5815 /* Reject invalid texture units */
5816 if (Stage >= GL_LIMITS(sampler_stages)) {
5817 TRACE("Attempt to access invalid texture rejected\n");
5818 return WINED3DERR_INVALIDCALL;
5820 *ppTexture=This->updateStateBlock->textures[Stage];
5821 if (*ppTexture)
5822 IWineD3DBaseTexture_AddRef(*ppTexture);
5823 else
5824 return WINED3DERR_INVALIDCALL;
5825 return WINED3D_OK;
5828 /*****
5829 * Get Back Buffer
5830 *****/
5831 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5832 IWineD3DSurface **ppBackBuffer) {
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5834 IWineD3DSwapChain *swapChain;
5835 HRESULT hr;
5837 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5839 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5840 if (hr == WINED3D_OK) {
5841 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5842 IWineD3DSwapChain_Release(swapChain);
5843 } else {
5844 *ppBackBuffer = NULL;
5846 return hr;
5849 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5851 WARN("(%p) : stub, calling idirect3d for now\n", This);
5852 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5855 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5857 IWineD3DSwapChain *swapChain;
5858 HRESULT hr;
5860 if(iSwapChain > 0) {
5861 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5862 if (hr == WINED3D_OK) {
5863 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5864 IWineD3DSwapChain_Release(swapChain);
5865 } else {
5866 FIXME("(%p) Error getting display mode\n", This);
5868 } else {
5869 /* Don't read the real display mode,
5870 but return the stored mode instead. X11 can't change the color
5871 depth, and some apps are pretty angry if they SetDisplayMode from
5872 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5874 Also don't relay to the swapchain because with ddraw it's possible
5875 that there isn't a swapchain at all */
5876 pMode->Width = This->ddraw_width;
5877 pMode->Height = This->ddraw_height;
5878 pMode->Format = This->ddraw_format;
5879 pMode->RefreshRate = 0;
5880 hr = WINED3D_OK;
5883 return hr;
5886 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5888 TRACE("(%p)->(%p)\n", This, hWnd);
5890 This->ddraw_window = hWnd;
5891 return WINED3D_OK;
5894 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 TRACE("(%p)->(%p)\n", This, hWnd);
5898 *hWnd = This->ddraw_window;
5899 return WINED3D_OK;
5902 /*****
5903 * Stateblock related functions
5904 *****/
5906 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5908 IWineD3DStateBlockImpl *object;
5909 HRESULT temp_result;
5911 TRACE("(%p)\n", This);
5913 if (This->isRecordingState) {
5914 return WINED3DERR_INVALIDCALL;
5917 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5918 if (NULL == object ) {
5919 FIXME("(%p)Error allocating memory for stateblock\n", This);
5920 return E_OUTOFMEMORY;
5922 TRACE("(%p) created object %p\n", This, object);
5923 object->wineD3DDevice= This;
5924 /** FIXME: object->parent = parent; **/
5925 object->parent = NULL;
5926 object->blockType = WINED3DSBT_ALL;
5927 object->ref = 1;
5928 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5930 temp_result = allocate_shader_constants(object);
5931 if (WINED3D_OK != temp_result)
5932 return temp_result;
5934 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5935 This->updateStateBlock = object;
5936 This->isRecordingState = TRUE;
5938 TRACE("(%p) recording stateblock %p\n",This , object);
5939 return WINED3D_OK;
5942 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5945 if (!This->isRecordingState) {
5946 FIXME("(%p) not recording! returning error\n", This);
5947 *ppStateBlock = NULL;
5948 return WINED3DERR_INVALIDCALL;
5951 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5952 This->isRecordingState = FALSE;
5953 This->updateStateBlock = This->stateBlock;
5954 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5955 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5956 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5957 return WINED3D_OK;
5960 /*****
5961 * Scene related functions
5962 *****/
5963 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5964 /* At the moment we have no need for any functionality at the beginning
5965 of a scene */
5966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5967 TRACE("(%p) : stub\n", This);
5968 return WINED3D_OK;
5971 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5973 TRACE("(%p)\n", This);
5974 ENTER_GL();
5975 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5976 glFlush();
5977 checkGLcall("glFlush");
5979 TRACE("End Scene\n");
5980 if(This->renderTarget != NULL) {
5982 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5983 IUnknown *targetContainer = NULL;
5984 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5985 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5986 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5987 /** always dirtify for now. we must find a better way to see that surface have been modified
5988 (Modifications should will only occur via draw-primitive, but we do need better locking
5989 switching to render-to-texture should remove the overhead though.
5991 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5992 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5993 IWineD3DSurface_PreLoad(This->renderTarget);
5994 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5995 IUnknown_Release(targetContainer);
5998 This->sceneEnded = TRUE;
5999 LEAVE_GL();
6000 return WINED3D_OK;
6003 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
6004 CONST RECT* pSourceRect, CONST RECT* pDestRect,
6005 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
6006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6007 IWineD3DSwapChain *swapChain = NULL;
6008 int i;
6009 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
6011 TRACE("(%p) Presenting the frame\n", This);
6013 for(i = 0 ; i < swapchains ; i ++) {
6015 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
6016 TRACE("presentinng chain %d, %p\n", i, swapChain);
6017 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
6018 IWineD3DSwapChain_Release(swapChain);
6021 return WINED3D_OK;
6024 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
6025 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
6026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6028 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
6029 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
6030 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6031 GLbitfield glMask = 0;
6032 GLboolean old_ztest;
6033 GLfloat old_z_clear_value;
6034 GLint old_stencil_clear_value;
6035 GLfloat old_color_clear_value[4];
6036 unsigned int i;
6037 CONST WINED3DRECT* curRect;
6039 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
6040 Count, pRects, Flags, Z, Stencil);
6042 ENTER_GL();
6044 glEnable(GL_SCISSOR_TEST);
6045 checkGLcall("glEnable GL_SCISSOR_TEST");
6047 if (Count > 0 && pRects) {
6048 curRect = pRects;
6049 } else {
6050 curRect = NULL;
6053 /* Only set the values up once, as they are not changing */
6054 if (Flags & D3DCLEAR_STENCIL) {
6055 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6056 glClearStencil(Stencil);
6057 checkGLcall("glClearStencil");
6058 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6059 glStencilMask(0xFFFFFFFF);
6062 if (Flags & D3DCLEAR_ZBUFFER) {
6063 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6064 glDepthMask(GL_TRUE);
6065 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6066 glClearDepth(Z);
6067 checkGLcall("glClearDepth");
6068 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6071 if (Flags & D3DCLEAR_TARGET) {
6072 TRACE("Clearing screen with glClear to color %x\n", Color);
6073 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6074 glClearColor(D3DCOLOR_R(Color),
6075 D3DCOLOR_G(Color),
6076 D3DCOLOR_B(Color),
6077 D3DCOLOR_A(Color));
6078 checkGLcall("glClearColor");
6080 /* Clear ALL colors! */
6081 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6082 glMask = glMask | GL_COLOR_BUFFER_BIT;
6085 /* Now process each rect in turn */
6086 for (i = 0; i < Count || i == 0; i++) {
6088 if (curRect) {
6089 /* Note gl uses lower left, width/height */
6090 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
6091 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6092 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6093 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6094 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6095 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6096 checkGLcall("glScissor");
6097 } else {
6098 glScissor(This->stateBlock->viewport.X,
6099 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6100 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6101 This->stateBlock->viewport.Width,
6102 This->stateBlock->viewport.Height);
6103 checkGLcall("glScissor");
6106 /* Clear the selected rectangle (or full screen) */
6107 glClear(glMask);
6108 checkGLcall("glClear");
6110 /* Step to the next rectangle */
6111 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
6114 /* Restore the old values (why..?) */
6115 if (Flags & D3DCLEAR_STENCIL) {
6116 glClearStencil(old_stencil_clear_value);
6117 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6119 if (Flags & D3DCLEAR_ZBUFFER) {
6120 glDepthMask(old_ztest);
6121 glClearDepth(old_z_clear_value);
6123 if (Flags & D3DCLEAR_TARGET) {
6124 glClearColor(old_color_clear_value[0],
6125 old_color_clear_value[1],
6126 old_color_clear_value[2],
6127 old_color_clear_value[3]);
6128 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6129 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6130 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6131 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6134 glDisable(GL_SCISSOR_TEST);
6135 checkGLcall("glDisable");
6136 LEAVE_GL();
6138 return WINED3D_OK;
6141 /*****
6142 * Drawing functions
6143 *****/
6144 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6145 UINT PrimitiveCount) {
6147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6148 This->stateBlock->streamIsUP = FALSE;
6150 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6151 debug_d3dprimitivetype(PrimitiveType),
6152 StartVertex, PrimitiveCount);
6153 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6154 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6157 return WINED3D_OK;
6160 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6161 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6162 WINED3DPRIMITIVETYPE PrimitiveType,
6163 INT baseVIndex, UINT minIndex,
6164 UINT NumVertices, UINT startIndex, UINT primCount) {
6166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6167 UINT idxStride = 2;
6168 IWineD3DIndexBuffer *pIB;
6169 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6171 pIB = This->stateBlock->pIndexData;
6172 This->stateBlock->streamIsUP = FALSE;
6174 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6175 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6176 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6178 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6179 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6180 idxStride = 2;
6181 } else {
6182 idxStride = 4;
6185 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6186 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6188 return WINED3D_OK;
6191 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6192 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6193 UINT VertexStreamZeroStride) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6196 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6197 debug_d3dprimitivetype(PrimitiveType),
6198 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6200 /* release the stream source */
6201 if (This->stateBlock->streamSource[0] != NULL) {
6202 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6205 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6206 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6207 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6208 This->stateBlock->streamIsUP = TRUE;
6210 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6211 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6213 /* MSDN specifies stream zero settings must be set to NULL */
6214 This->stateBlock->streamStride[0] = 0;
6215 This->stateBlock->streamSource[0] = NULL;
6217 /*stream zero settings set to null at end, as per the msdn */
6218 return WINED3D_OK;
6221 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6222 UINT MinVertexIndex, UINT NumVertices,
6223 UINT PrimitiveCount, CONST void* pIndexData,
6224 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6225 UINT VertexStreamZeroStride) {
6226 int idxStride;
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6229 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6230 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6231 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6232 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6234 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6235 idxStride = 2;
6236 } else {
6237 idxStride = 4;
6240 /* release the stream and index data */
6241 if (This->stateBlock->streamSource[0] != NULL) {
6242 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6244 if (This->stateBlock->pIndexData) {
6245 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6248 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6249 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6250 This->stateBlock->streamIsUP = TRUE;
6251 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6253 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6255 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6256 This->stateBlock->streamSource[0] = NULL;
6257 This->stateBlock->streamStride[0] = 0;
6258 This->stateBlock->pIndexData = NULL;
6260 return WINED3D_OK;
6263 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6265 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6266 return WINED3D_OK;
6268 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6269 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6271 HRESULT hr = WINED3D_OK;
6272 WINED3DRESOURCETYPE sourceType;
6273 WINED3DRESOURCETYPE destinationType;
6274 int i ,levels;
6276 /* TODO: think about moving the code into IWineD3DBaseTexture */
6278 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6280 /* verify that the source and destination textures aren't NULL */
6281 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6282 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6283 This, pSourceTexture, pDestinationTexture);
6284 hr = WINED3DERR_INVALIDCALL;
6287 if (pSourceTexture == pDestinationTexture) {
6288 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6289 This, pSourceTexture, pDestinationTexture);
6290 hr = WINED3DERR_INVALIDCALL;
6292 /* Verify that the source and destination textures are the same type */
6293 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6294 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6296 if (sourceType != destinationType) {
6297 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6298 This);
6299 hr = WINED3DERR_INVALIDCALL;
6302 /* check that both textures have the identical numbers of levels */
6303 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6304 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6305 hr = WINED3DERR_INVALIDCALL;
6308 if (WINED3D_OK == hr) {
6310 /* Make sure that the destination texture is loaded */
6311 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6313 /* Update every surface level of the texture */
6314 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6316 switch (sourceType) {
6317 case WINED3DRTYPE_TEXTURE:
6319 IWineD3DSurface *srcSurface;
6320 IWineD3DSurface *destSurface;
6322 for (i = 0 ; i < levels ; ++i) {
6323 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6324 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6325 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6326 IWineD3DSurface_Release(srcSurface);
6327 IWineD3DSurface_Release(destSurface);
6328 if (WINED3D_OK != hr) {
6329 WARN("(%p) : Call to update surface failed\n", This);
6330 return hr;
6334 break;
6335 case WINED3DRTYPE_CUBETEXTURE:
6337 IWineD3DSurface *srcSurface;
6338 IWineD3DSurface *destSurface;
6339 WINED3DCUBEMAP_FACES faceType;
6341 for (i = 0 ; i < levels ; ++i) {
6342 /* Update each cube face */
6343 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6344 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6345 if (WINED3D_OK != hr) {
6346 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6347 } else {
6348 TRACE("Got srcSurface %p\n", srcSurface);
6350 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6351 if (WINED3D_OK != hr) {
6352 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6353 } else {
6354 TRACE("Got desrSurface %p\n", destSurface);
6356 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6357 IWineD3DSurface_Release(srcSurface);
6358 IWineD3DSurface_Release(destSurface);
6359 if (WINED3D_OK != hr) {
6360 WARN("(%p) : Call to update surface failed\n", This);
6361 return hr;
6366 break;
6367 #if 0 /* TODO: Add support for volume textures */
6368 case WINED3DRTYPE_VOLUMETEXTURE:
6370 IWineD3DVolume srcVolume = NULL;
6371 IWineD3DSurface destVolume = NULL;
6373 for (i = 0 ; i < levels ; ++i) {
6374 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6375 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6376 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6377 IWineD3DVolume_Release(srcSurface);
6378 IWineD3DVolume_Release(destSurface);
6379 if (WINED3D_OK != hr) {
6380 WARN("(%p) : Call to update volume failed\n", This);
6381 return hr;
6385 break;
6386 #endif
6387 default:
6388 FIXME("(%p) : Unsupported source and destination type\n", This);
6389 hr = WINED3DERR_INVALIDCALL;
6393 return hr;
6396 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6397 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6398 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6401 TRACE("(%p) : stub\n", This);
6402 return WINED3D_OK;
6404 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6406 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6407 * NOTE It may be best to move the code into surface to occomplish this
6408 ****************************************/
6410 WINED3DSURFACE_DESC surfaceDesc;
6411 unsigned int surfaceWidth, surfaceHeight;
6412 glDescriptor *targetGlDescription = NULL;
6413 glDescriptor *surfaceGlDescription = NULL;
6414 IWineD3DSwapChainImpl *container = NULL;
6416 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6417 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6418 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6420 surfaceDesc.Width = &surfaceWidth;
6421 surfaceDesc.Height = &surfaceHeight;
6422 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6423 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6425 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6426 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6427 ENTER_GL();
6428 /* TODO: opengl Context switching for swapchains etc... */
6429 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6430 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6431 glReadBuffer(GL_BACK);
6432 vcheckGLcall("glReadBuffer(GL_BACK)");
6433 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6434 glReadBuffer(GL_FRONT);
6435 vcheckGLcall("glReadBuffer(GL_FRONT)");
6436 } else if (pRenderTarget == This->depthStencilBuffer) {
6437 FIXME("Reading of depthstencil not yet supported\n");
6440 glReadPixels(surfaceGlDescription->target,
6441 surfaceGlDescription->level,
6442 surfaceWidth,
6443 surfaceHeight,
6444 surfaceGlDescription->glFormat,
6445 surfaceGlDescription->glType,
6446 (void *)IWineD3DSurface_GetData(pSurface));
6447 vcheckGLcall("glReadPixels(...)");
6448 if(NULL != container ){
6449 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6451 } else {
6452 IWineD3DBaseTexture *container;
6453 GLenum textureDimensions = GL_TEXTURE_2D;
6455 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6456 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6457 IWineD3DBaseTexture_Release(container);
6459 /* TODO: 2D -> Cube surface coppies etc.. */
6460 if (surfaceGlDescription->target != textureDimensions) {
6461 FIXME("(%p) : Texture dimension mismatch\n", This);
6463 glEnable(textureDimensions);
6464 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6465 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6466 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6467 vcheckGLcall("glBindTexture");
6468 glGetTexImage(surfaceGlDescription->target,
6469 surfaceGlDescription->level,
6470 surfaceGlDescription->glFormat,
6471 surfaceGlDescription->glType,
6472 (void *)IWineD3DSurface_GetData(pSurface));
6473 glDisable(textureDimensions);
6474 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6477 LEAVE_GL();
6478 return WINED3D_OK;
6481 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6482 IWineD3DSwapChain *swapChain;
6483 HRESULT hr;
6484 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6485 if(hr == WINED3D_OK) {
6486 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6487 IWineD3DSwapChain_Release(swapChain);
6489 return hr;
6492 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6494 /* return a sensible default */
6495 *pNumPasses = 1;
6496 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6497 FIXME("(%p) : stub\n", This);
6498 return WINED3D_OK;
6501 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6503 int j;
6504 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6505 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6506 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6507 return WINED3DERR_INVALIDCALL;
6509 for (j = 0; j < 256; ++j) {
6510 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6511 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6512 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6513 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6515 TRACE("(%p) : returning\n", This);
6516 return WINED3D_OK;
6519 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6521 int j;
6522 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6523 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6524 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6525 return WINED3DERR_INVALIDCALL;
6527 for (j = 0; j < 256; ++j) {
6528 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6529 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6530 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6531 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6533 TRACE("(%p) : returning\n", This);
6534 return WINED3D_OK;
6537 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6539 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6540 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6541 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6542 return WINED3DERR_INVALIDCALL;
6544 /*TODO: stateblocks */
6545 This->currentPalette = PaletteNumber;
6546 TRACE("(%p) : returning\n", This);
6547 return WINED3D_OK;
6550 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6552 if (PaletteNumber == NULL) {
6553 WARN("(%p) : returning Invalid Call\n", This);
6554 return WINED3DERR_INVALIDCALL;
6556 /*TODO: stateblocks */
6557 *PaletteNumber = This->currentPalette;
6558 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6559 return WINED3D_OK;
6562 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6564 static BOOL showFixmes = TRUE;
6565 if (showFixmes) {
6566 FIXME("(%p) : stub\n", This);
6567 showFixmes = FALSE;
6570 This->softwareVertexProcessing = bSoftware;
6571 return WINED3D_OK;
6575 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6577 static BOOL showFixmes = TRUE;
6578 if (showFixmes) {
6579 FIXME("(%p) : stub\n", This);
6580 showFixmes = FALSE;
6582 return This->softwareVertexProcessing;
6586 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6588 IWineD3DSwapChain *swapChain;
6589 HRESULT hr;
6591 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6593 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6594 if(hr == WINED3D_OK){
6595 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6596 IWineD3DSwapChain_Release(swapChain);
6597 }else{
6598 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6600 return hr;
6604 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6606 static BOOL showfixmes = TRUE;
6607 if(nSegments != 0.0f) {
6608 if( showfixmes) {
6609 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6610 showfixmes = FALSE;
6613 return WINED3D_OK;
6616 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6618 static BOOL showfixmes = TRUE;
6619 if( showfixmes) {
6620 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6621 showfixmes = FALSE;
6623 return 0.0f;
6626 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6628 /** TODO: remove casts to IWineD3DSurfaceImpl
6629 * NOTE: move code to surface to accomplish this
6630 ****************************************/
6631 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6632 int srcWidth, srcHeight;
6633 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6634 WINED3DFORMAT destFormat, srcFormat;
6635 UINT destSize;
6636 int destLeft, destTop;
6637 WINED3DPOOL srcPool, destPool;
6638 int offset = 0;
6639 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6640 glDescriptor *glDescription = NULL;
6641 GLenum textureDimensions = GL_TEXTURE_2D;
6642 IWineD3DBaseTexture *baseTexture;
6644 WINED3DSURFACE_DESC winedesc;
6646 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6647 memset(&winedesc, 0, sizeof(winedesc));
6648 winedesc.Width = &srcSurfaceWidth;
6649 winedesc.Height = &srcSurfaceHeight;
6650 winedesc.Pool = &srcPool;
6651 winedesc.Format = &srcFormat;
6653 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6655 winedesc.Width = &destSurfaceWidth;
6656 winedesc.Height = &destSurfaceHeight;
6657 winedesc.Pool = &destPool;
6658 winedesc.Format = &destFormat;
6659 winedesc.Size = &destSize;
6661 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6663 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6664 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6665 return WINED3DERR_INVALIDCALL;
6668 if (destFormat == WINED3DFMT_UNKNOWN) {
6669 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6670 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6672 /* Get the update surface description */
6673 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6676 /* Make sure the surface is loaded and up to date */
6677 IWineD3DSurface_PreLoad(pDestinationSurface);
6679 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6681 ENTER_GL();
6683 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6684 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6685 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6686 destLeft = pDestPoint ? pDestPoint->x : 0;
6687 destTop = pDestPoint ? pDestPoint->y : 0;
6690 /* This function doesn't support compressed textures
6691 the pitch is just bytesPerPixel * width */
6692 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6693 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6694 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6695 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6697 /* TODO DXT formats */
6699 if(pSourceRect != NULL && pSourceRect->top != 0){
6700 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6702 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6703 ,This
6704 ,glDescription->level
6705 ,destLeft
6706 ,destTop
6707 ,srcWidth
6708 ,srcHeight
6709 ,glDescription->glFormat
6710 ,glDescription->glType
6711 ,IWineD3DSurface_GetData(pSourceSurface)
6714 /* Sanity check */
6715 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6717 /* need to lock the surface to get the data */
6718 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6721 /* TODO: Cube and volume support */
6722 if(rowoffset != 0){
6723 /* not a whole row so we have to do it a line at a time */
6724 int j;
6726 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6727 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6729 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6731 glTexSubImage2D(glDescription->target
6732 ,glDescription->level
6733 ,destLeft
6735 ,srcWidth
6737 ,glDescription->glFormat
6738 ,glDescription->glType
6739 ,data /* could be quicker using */
6741 data += rowoffset;
6744 } else { /* Full width, so just write out the whole texture */
6746 if (WINED3DFMT_DXT1 == destFormat ||
6747 WINED3DFMT_DXT2 == destFormat ||
6748 WINED3DFMT_DXT3 == destFormat ||
6749 WINED3DFMT_DXT4 == destFormat ||
6750 WINED3DFMT_DXT5 == destFormat) {
6751 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6752 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6753 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6754 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6755 } if (destFormat != srcFormat) {
6756 FIXME("Updating mixed format compressed texture is not curretly support\n");
6757 } else {
6758 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6759 glDescription->level,
6760 glDescription->glFormatInternal,
6761 srcWidth,
6762 srcHeight,
6764 destSize,
6765 IWineD3DSurface_GetData(pSourceSurface));
6767 } else {
6768 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6772 } else {
6773 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6775 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6776 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6777 data returned by GetData non-power2 width/height with hardware non-power2
6778 pow2Width/height are set to surface width height, repacking isn't needed so it
6779 doesn't matter which function gets called. */
6780 glTexSubImage2D(glDescription->target
6781 ,glDescription->level
6782 ,destLeft
6783 ,destTop
6784 ,srcWidth
6785 ,srcHeight
6786 ,glDescription->glFormat
6787 ,glDescription->glType
6788 ,IWineD3DSurface_GetData(pSourceSurface)
6790 } else {
6792 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6793 glTexSubImage2D(glDescription->target
6794 ,glDescription->level
6795 ,destLeft
6796 ,destTop
6797 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6798 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6799 ,glDescription->glFormat
6800 ,glDescription->glType
6801 ,IWineD3DSurface_GetData(pSourceSurface)
6807 checkGLcall("glTexSubImage2D");
6808 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6810 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6811 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6812 * surface bigger than it needs to be hmm.. */
6813 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6814 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6815 IWineD3DBaseTexture_Release(baseTexture);
6818 glDisable(textureDimensions); /* This needs to be managed better.... */
6819 LEAVE_GL();
6821 return WINED3D_OK;
6824 /* Used by DirectX 8 */
6825 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6826 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6827 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6830 HRESULT hr = WINED3D_OK;
6831 WINED3DFORMAT srcFormat, destFormat;
6832 UINT srcWidth, destWidth;
6833 UINT srcHeight, destHeight;
6834 UINT srcSize;
6835 WINED3DSURFACE_DESC winedesc;
6837 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6838 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6841 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6842 memset(&winedesc, 0, sizeof(winedesc));
6844 winedesc.Format = &srcFormat;
6845 winedesc.Width = &srcWidth;
6846 winedesc.Height = &srcHeight;
6847 winedesc.Size = &srcSize;
6848 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6850 winedesc.Format = &destFormat;
6851 winedesc.Width = &destWidth;
6852 winedesc.Height = &destHeight;
6853 winedesc.Size = NULL;
6854 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6856 /* Check that the source and destination formats match */
6857 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6858 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6859 return WINED3DERR_INVALIDCALL;
6860 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6861 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6862 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6863 destFormat = srcFormat;
6866 /* Quick if complete copy ... */
6867 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6869 if (srcWidth == destWidth && srcHeight == destHeight) {
6870 WINED3DLOCKED_RECT lrSrc;
6871 WINED3DLOCKED_RECT lrDst;
6872 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6873 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6874 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6876 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6878 IWineD3DSurface_UnlockRect(pSourceSurface);
6879 IWineD3DSurface_UnlockRect(pDestinationSurface);
6880 TRACE("Unlocked src and dst\n");
6882 } else {
6884 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6885 hr = WINED3DERR_INVALIDCALL;
6888 } else {
6890 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6892 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6893 unsigned int i;
6895 /* Copy rect by rect */
6896 for (i = 0; i < cRects; ++i) {
6897 CONST RECT* r = &pSourceRectsArray[i];
6898 CONST POINT* p = &pDestPointsArray[i];
6899 int copyperline;
6900 int j;
6901 WINED3DLOCKED_RECT lrSrc;
6902 WINED3DLOCKED_RECT lrDst;
6903 RECT dest_rect;
6905 TRACE("Copying rect %d (%d,%d),(%d,%d) -> (%d,%d)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6906 if (srcFormat == WINED3DFMT_DXT1) {
6907 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6908 } else {
6909 copyperline = ((r->right - r->left) * bytesPerPixel);
6912 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6913 dest_rect.left = p->x;
6914 dest_rect.top = p->y;
6915 dest_rect.right = p->x + (r->right - r->left);
6916 dest_rect.bottom= p->y + (r->bottom - r->top);
6917 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6918 TRACE("Locked src and dst\n");
6920 /* Find where to start */
6921 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6922 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6924 IWineD3DSurface_UnlockRect(pSourceSurface);
6925 IWineD3DSurface_UnlockRect(pDestinationSurface);
6926 TRACE("Unlocked src and dst\n");
6928 } else {
6929 unsigned int i;
6930 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6931 int copyperline;
6932 int j;
6933 WINED3DLOCKED_RECT lrSrc;
6934 WINED3DLOCKED_RECT lrDst;
6935 RECT dest_rect;
6937 for(i=0; i < cRects; i++) {
6938 CONST RECT* r = &pSourceRectsArray[i];
6940 TRACE("Copying rect %d (%d,%d),(%d,%d) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6941 if (srcFormat == WINED3DFMT_DXT1) {
6942 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6943 } else {
6944 copyperline = ((r->right - r->left) * bytesPerPixel);
6946 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6947 dest_rect.left = 0;
6948 dest_rect.top = 0;
6949 dest_rect.right = r->right - r->left;
6950 dest_rect.bottom= r->bottom - r->top;
6951 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6952 TRACE("Locked src and dst\n");
6953 /* Find where to start */
6954 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6955 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6957 IWineD3DSurface_UnlockRect(pSourceSurface);
6958 IWineD3DSurface_UnlockRect(pDestinationSurface);
6959 TRACE("Unlocked src and dst\n");
6964 return hr;
6967 /* Implementation details at http://developer.nvidia.com/attach/6494
6969 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6970 hmm.. no longer supported use
6971 OpenGL evaluators or tessellate surfaces within your application.
6974 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6975 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6977 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6978 FIXME("(%p) : Stub\n", This);
6979 return WINED3D_OK;
6983 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6984 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6986 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6987 FIXME("(%p) : Stub\n", This);
6988 return WINED3D_OK;
6991 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6993 TRACE("(%p) Handle(%d)\n", This, Handle);
6994 FIXME("(%p) : Stub\n", This);
6995 return WINED3D_OK;
6998 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7000 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
7001 DDBLTFX BltFx;
7002 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
7004 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
7005 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
7006 return WINED3DERR_INVALIDCALL;
7009 /* Just forward this to the DirectDraw blitting engine */
7010 memset(&BltFx, 0, sizeof(BltFx));
7011 BltFx.dwSize = sizeof(BltFx);
7012 BltFx.u5.dwFillColor = color;
7013 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
7016 /* rendertarget and deptth stencil functions */
7017 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
7018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7020 /* FIXME: Implelent RenderTargetIndex >0 */
7021 if(RenderTargetIndex > 0)
7022 FIXME("(%p) : RenderTargetIndex %d >0 not currently supported\n", This, RenderTargetIndex);
7024 *ppRenderTarget = This->renderTarget;
7025 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
7026 /* Note inc ref on returned surface */
7027 if(*ppRenderTarget != NULL)
7028 IWineD3DSurface_AddRef(*ppRenderTarget);
7029 return WINED3D_OK;
7032 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
7033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7034 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
7035 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
7036 IWineD3DSwapChainImpl *Swapchain;
7037 HRESULT hr;
7039 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
7041 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
7042 if(hr != WINED3D_OK) {
7043 ERR("Can't get the swapchain\n");
7044 return hr;
7047 /* Make sure to release the swapchain */
7048 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
7050 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
7051 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7052 return WINED3DERR_INVALIDCALL;
7054 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7055 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7056 return WINED3DERR_INVALIDCALL;
7059 if(Swapchain->frontBuffer != Front) {
7060 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7062 if(Swapchain->frontBuffer)
7063 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7064 Swapchain->frontBuffer = Front;
7066 if(Swapchain->frontBuffer) {
7067 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7071 if(Back && !Swapchain->backBuffer) {
7072 /* We need memory for the back buffer array - only one back buffer this way */
7073 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7074 if(!Swapchain->backBuffer) {
7075 ERR("Out of memory\n");
7076 return E_OUTOFMEMORY;
7080 if(Swapchain->backBuffer[0] != Back) {
7081 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7082 ENTER_GL();
7083 if(!Swapchain->backBuffer[0]) {
7084 /* GL was told to draw to the front buffer at creation,
7085 * undo that
7087 glDrawBuffer(GL_BACK);
7088 checkGLcall("glDrawBuffer(GL_BACK)");
7089 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7090 Swapchain->presentParms.BackBufferCount = 1;
7091 } else if (!Back) {
7092 /* That makes problems - disable for now */
7093 /* glDrawBuffer(GL_FRONT); */
7094 checkGLcall("glDrawBuffer(GL_FRONT)");
7095 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7096 Swapchain->presentParms.BackBufferCount = 0;
7098 LEAVE_GL();
7100 if(Swapchain->backBuffer[0])
7101 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7102 Swapchain->backBuffer[0] = Back;
7104 if(Swapchain->backBuffer[0]) {
7105 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7106 } else {
7107 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7112 return WINED3D_OK;
7115 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7117 *ppZStencilSurface = This->depthStencilBuffer;
7118 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7120 if(*ppZStencilSurface != NULL) {
7121 /* Note inc ref on returned surface */
7122 IWineD3DSurface_AddRef(*ppZStencilSurface);
7124 return WINED3D_OK;
7127 /* internal static helper functions */
7128 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7129 IWineD3DSurface *RenderSurface);
7131 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7133 HRESULT hr = WINED3D_OK;
7134 WINED3DVIEWPORT viewport;
7136 TRACE("(%p) Swapping rendertarget\n",This);
7137 if (RenderTargetIndex > 0) {
7138 FIXME("(%p) Render targets other than the first are not supported\n",This);
7139 RenderTargetIndex = 0;
7142 /* MSDN says that null disables the render target
7143 but a device must always be associated with a render target
7144 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7146 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7147 for more details
7149 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7150 FIXME("Trying to set render target 0 to NULL\n");
7151 return WINED3DERR_INVALIDCALL;
7153 /* TODO: replace Impl* usage with interface usage */
7154 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7155 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);
7156 return WINED3DERR_INVALIDCALL;
7158 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7159 * builds, but I think wine counts as a 'debug' build for now.
7160 ******************************/
7161 /* If we are trying to set what we already have, don't bother */
7162 if (pRenderTarget == This->renderTarget) {
7163 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7164 } else {
7165 /* Otherwise, set the render target up */
7167 if (!This->sceneEnded) {
7168 IWineD3DDevice_EndScene(iface);
7170 TRACE("clearing renderer\n");
7171 /* IWineD3DDeviceImpl_CleanRender(iface); */
7172 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7173 depending on the renter target implementation being used.
7174 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7175 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7176 stencil buffer and incure an extra memory overhead */
7177 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7180 if (SUCCEEDED(hr)) {
7181 /* Finally, reset the viewport as the MSDN states. */
7182 /* TODO: Replace impl usage */
7183 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7184 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7185 viewport.X = 0;
7186 viewport.Y = 0;
7187 viewport.MaxZ = 1.0f;
7188 viewport.MinZ = 0.0f;
7189 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7190 } else {
7191 FIXME("Unknown error setting the render target\n");
7193 This->sceneEnded = FALSE;
7194 return hr;
7197 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7199 HRESULT hr = WINED3D_OK;
7200 IWineD3DSurface *tmp;
7202 TRACE("(%p) Swapping z-buffer\n",This);
7204 if (pNewZStencil == This->stencilBufferTarget) {
7205 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7206 } else {
7207 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7208 * depending on the renter target implementation being used.
7209 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7210 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7211 * stencil buffer and incure an extra memory overhead
7212 ******************************************************/
7215 tmp = This->stencilBufferTarget;
7216 This->stencilBufferTarget = pNewZStencil;
7217 /* should we be calling the parent or the wined3d surface? */
7218 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7219 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7220 hr = WINED3D_OK;
7221 /** TODO: glEnable/glDisable on depth/stencil depending on
7222 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7223 **********************************************************/
7226 return hr;
7230 #ifdef GL_VERSION_1_3
7231 /* Internal functions not in DirectX */
7232 /** TODO: move this off to the opengl context manager
7233 *(the swapchain doesn't need to know anything about offscreen rendering!)
7234 ****************************************************/
7236 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7240 TRACE("(%p), %p\n", This, swapchain);
7242 if (swapchain->win != swapchain->drawable) {
7243 /* Set everything back the way it ws */
7244 swapchain->render_ctx = swapchain->glCtx;
7245 swapchain->drawable = swapchain->win;
7247 return WINED3D_OK;
7250 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7251 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7253 int i;
7254 unsigned int width;
7255 unsigned int height;
7256 WINED3DFORMAT format;
7257 WINED3DSURFACE_DESC surfaceDesc;
7258 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7259 surfaceDesc.Width = &width;
7260 surfaceDesc.Height = &height;
7261 surfaceDesc.Format = &format;
7262 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7263 *context = NULL;
7264 /* I need a get width/height function (and should do something with the format) */
7265 for (i = 0; i < CONTEXT_CACHE; ++i) {
7266 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7267 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7268 the pSurface can be set to 0 allowing it to be reused from cache **/
7269 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7270 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7271 *context = &This->contextCache[i];
7272 break;
7274 if (This->contextCache[i].Width == 0) {
7275 This->contextCache[i].pSurface = pSurface;
7276 This->contextCache[i].Width = width;
7277 This->contextCache[i].Height = height;
7278 *context = &This->contextCache[i];
7279 break;
7282 if (i == CONTEXT_CACHE) {
7283 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7284 glContext *dropContext = 0;
7285 for (i = 0; i < CONTEXT_CACHE; i++) {
7286 if (This->contextCache[i].usedcount < minUsage) {
7287 dropContext = &This->contextCache[i];
7288 minUsage = This->contextCache[i].usedcount;
7291 /* clean up the context (this doesn't work for ATI at the moment */
7292 #if 0
7293 glXDestroyContext(swapchain->display, dropContext->context);
7294 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7295 #endif
7296 FIXME("Leak\n");
7297 dropContext->Width = 0;
7298 dropContext->pSurface = pSurface;
7299 *context = dropContext;
7300 } else {
7301 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7302 for (i = 0; i < CONTEXT_CACHE; i++) {
7303 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7307 if (*context != NULL)
7308 return WINED3D_OK;
7309 else
7310 return E_OUTOFMEMORY;
7312 #endif
7314 /* Reapply the device stateblock */
7315 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7317 BOOL oldRecording;
7318 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7320 /* Disable recording */
7321 oldUpdateStateBlock = This->updateStateBlock;
7322 oldRecording= This->isRecordingState;
7323 This->isRecordingState = FALSE;
7324 This->updateStateBlock = This->stateBlock;
7326 /* Reapply the state block */
7327 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7329 /* Restore recording */
7330 This->isRecordingState = oldRecording;
7331 This->updateStateBlock = oldUpdateStateBlock;
7334 /* Set the device to render to a texture, or not.
7335 * This involves changing renderUpsideDown */
7337 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7339 DWORD cullMode;
7340 BOOL oldRecording;
7341 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7343 /* Disable recording */
7344 oldUpdateStateBlock = This->updateStateBlock;
7345 oldRecording= This->isRecordingState;
7346 This->isRecordingState = FALSE;
7347 This->updateStateBlock = This->stateBlock;
7349 /* Set upside-down rendering, and update the cull mode */
7350 /* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
7351 This->renderUpsideDown = isTexture;
7352 This->last_was_rhw = FALSE;
7353 This->proj_valid = FALSE;
7354 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7355 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7357 /* Restore recording */
7358 This->isRecordingState = oldRecording;
7359 This->updateStateBlock = oldUpdateStateBlock;
7362 /* Returns an array of compatible FBconfig(s).
7363 * The array must be freed with XFree. Requires ENTER_GL() */
7365 static GLXFBConfig* device_find_fbconfigs(
7366 IWineD3DDeviceImpl* This,
7367 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7368 IWineD3DSurface* RenderSurface) {
7370 GLXFBConfig* cfgs = NULL;
7371 int nCfgs = 0;
7372 int attribs[256];
7373 int nAttribs = 0;
7375 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7376 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7377 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7379 /**TODO:
7380 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7381 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7384 #define PUSH1(att) attribs[nAttribs++] = (att);
7385 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7387 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7389 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7390 PUSH2(GLX_X_RENDERABLE, TRUE);
7391 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7392 TRACE("calling makeglcfg\n");
7393 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7394 PUSH1(None);
7395 TRACE("calling chooseFGConfig\n");
7396 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7397 DefaultScreen(implicitSwapchainImpl->display),
7398 attribs, &nCfgs);
7399 if (cfgs == NULL) {
7400 /* OK we didn't find the exact config, so use any reasonable match */
7401 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
7402 why we failed. */
7403 static BOOL show_message = TRUE;
7404 if (show_message) {
7405 ERR("Failed to find exact match, finding alternative but you may "
7406 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7407 show_message = FALSE;
7409 nAttribs = 0;
7410 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7411 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7412 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7413 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7414 TRACE("calling makeglcfg\n");
7415 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7416 PUSH1(None);
7417 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7418 DefaultScreen(implicitSwapchainImpl->display),
7419 attribs, &nCfgs);
7422 if (cfgs == NULL) {
7423 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7424 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7425 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7426 } else {
7427 #ifdef EXTRA_TRACES
7428 int i;
7429 for (i = 0; i < nCfgs; ++i) {
7430 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7431 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7432 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7434 if (NULL != This->renderTarget) {
7435 glFlush();
7436 vcheckGLcall("glFlush");
7437 /** This is only useful if the old render target was a swapchain,
7438 * we need to supercede this with a function that displays
7439 * the current buffer on the screen. This is easy to do in glx1.3 but
7440 * we need to do copy-write pixels in glx 1.2.
7441 ************************************************/
7442 glXSwapBuffers(implicitSwapChainImpl->display,
7443 implicitSwapChainImpl->drawable);
7444 printf("Hit Enter to get next frame ...\n");
7445 getchar();
7447 #endif
7449 #undef PUSH1
7450 #undef PUSH2
7452 return cfgs;
7455 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7456 * the functionality needs splitting up so that we don't do more than we should do.
7457 * this only seems to impact performance a little.
7458 ******************************/
7459 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7460 IWineD3DSurface *RenderSurface) {
7463 * Currently only active for GLX >= 1.3
7464 * for others versions we'll have to use GLXPixmaps
7466 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7467 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7468 * so only check OpenGL version
7469 * ..........................
7470 * I don't believe that it is a problem with NVidia headers,
7471 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7472 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7473 * ATI Note:
7474 * Your application will report GLX version 1.2 on glXQueryVersion.
7475 * However, it is safe to call the GLX 1.3 functions as described below.
7477 #if defined(GL_VERSION_1_3)
7479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7480 GLXFBConfig* cfgs = NULL;
7481 IWineD3DSwapChain *currentSwapchain;
7482 IWineD3DSwapChainImpl *currentSwapchainImpl;
7483 IWineD3DSwapChain *implicitSwapchain;
7484 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7485 IWineD3DSwapChain *renderSurfaceSwapchain;
7486 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7488 /* Obtain a reference to the device implicit swapchain,
7489 * the swapchain of the current render target,
7490 * and the swapchain of the new render target.
7491 * Fallback to device implicit swapchain if the current render target doesn't have one */
7492 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7493 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7494 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
7495 if (currentSwapchain == NULL)
7496 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7498 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7499 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7500 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7502 ENTER_GL();
7505 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7506 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7507 **********************************************************************/
7508 if (renderSurfaceSwapchain != NULL) {
7510 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7511 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7512 TRACE("making swapchain active\n");
7513 if (RenderSurface != This->renderTarget) {
7514 BOOL backbuf = FALSE;
7515 int i;
7517 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7518 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7519 backbuf = TRUE;
7520 break;
7524 if (backbuf) {
7525 } else {
7526 /* This could be flagged so that some operations work directly with the front buffer */
7527 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7529 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7530 renderSurfaceSwapchainImpl->win,
7531 renderSurfaceSwapchainImpl->glCtx) == False) {
7533 TRACE("Error in setting current context: context %p drawable %ld !\n",
7534 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7536 checkGLcall("glXMakeContextCurrent");
7538 /* Clean up the old context */
7539 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7541 /* Reapply the stateblock, and set the device not to render to texture */
7542 device_reapply_stateblock(This);
7543 device_render_to_texture(This, FALSE);
7546 /* Offscreen rendering: PBuffers (currently disabled).
7547 * Also note that this path is never reached if FBOs are supported */
7548 } else if (pbuffer_support &&
7549 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7551 /** ********************************************************************
7552 * This is a quickly hacked out implementation of offscreen textures.
7553 * It will work in most cases but there may be problems if the client
7554 * modifies the texture directly, or expects the contents of the rendertarget
7555 * to be persistent.
7557 * There are some real speed vs compatibility issues here:
7558 * we should really use a new context for every texture, but that eats ram.
7559 * we should also be restoring the texture to the pbuffer but that eats CPU
7560 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7561 * but if this means reusing the display backbuffer then we need to make sure that
7562 * states are correctly preserved.
7563 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7564 * and gain a good performance increase at the cost of compatibility.
7565 * I would suggest that, when this is the case, a user configurable flag be made
7566 * available, allowing the user to choose the best emulated experience for them.
7567 *********************************************************************/
7569 XVisualInfo *visinfo;
7570 glContext *newContext;
7572 /* Here were using a shared context model */
7573 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7574 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7577 /* If the context doesn't exist then create a new one */
7578 /* TODO: This should really be part of findGlContext */
7579 if (NULL == newContext->context) {
7581 int attribs[256];
7582 int nAttribs = 0;
7584 TRACE("making new buffer\n");
7585 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7586 attribs[nAttribs++] = newContext->Width;
7587 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7588 attribs[nAttribs++] = newContext->Height;
7589 attribs[nAttribs++] = None;
7591 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7593 /** ****************************************
7594 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7595 *they note:
7596 * In future releases, we may provide the calls glXCreateNewContext,
7597 * glXQueryDrawable and glXMakeContextCurrent.
7598 * so until then we have to use glXGetVisualFromFBConfig &co..
7599 ********************************************/
7601 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7602 if (!visinfo) {
7603 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7604 } else {
7605 newContext->context = glXCreateContext(
7606 implicitSwapchainImpl->display, visinfo,
7607 implicitSwapchainImpl->glCtx, GL_TRUE);
7609 XFree(visinfo);
7612 if (NULL == newContext || NULL == newContext->context) {
7613 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7614 } else {
7615 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7616 if (glXMakeCurrent(implicitSwapchainImpl->display,
7617 newContext->drawable, newContext->context) == False) {
7619 TRACE("Error in setting current context: context %p drawable %ld\n",
7620 newContext->context, newContext->drawable);
7622 checkGLcall("glXMakeContextCurrent");
7624 /* Clean up the old context */
7625 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7627 /* Reapply stateblock, and set device to render to a texture */
7628 device_reapply_stateblock(This);
7629 device_render_to_texture(This, TRUE);
7631 /* Set the current context of the swapchain to the new context */
7632 implicitSwapchainImpl->drawable = newContext->drawable;
7633 implicitSwapchainImpl->render_ctx = newContext->context;
7635 } else {
7636 /* Same context, but update renderUpsideDown and cull mode */
7637 device_render_to_texture(This, TRUE);
7640 /* Replace the render target */
7641 if (This->renderTarget != RenderSurface) {
7642 IWineD3DSurface_Release(This->renderTarget);
7643 This->renderTarget = RenderSurface;
7644 IWineD3DSurface_AddRef(RenderSurface);
7647 if (cfgs != NULL) XFree(cfgs);
7648 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
7649 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7650 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7651 LEAVE_GL();
7652 #endif
7653 return WINED3D_OK;
7656 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7657 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7659 /* TODO: the use of Impl is deprecated. */
7660 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7662 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7664 /* some basic validation checks */
7665 if(This->cursorTexture) {
7666 ENTER_GL();
7667 glDeleteTextures(1, &This->cursorTexture);
7668 LEAVE_GL();
7669 This->cursorTexture = 0;
7672 if(pCursorBitmap) {
7673 /* MSDN: Cursor must be A8R8G8B8 */
7674 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7675 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7676 return WINED3DERR_INVALIDCALL;
7679 /* MSDN: Cursor must be smaller than the display mode */
7680 if(pSur->currentDesc.Width > This->ddraw_width ||
7681 pSur->currentDesc.Height > This->ddraw_height) {
7682 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7683 return WINED3DERR_INVALIDCALL;
7686 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7687 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7688 * Texture and Blitting code to draw the cursor
7690 pSur->Flags |= SFLAG_FORCELOAD;
7691 IWineD3DSurface_PreLoad(pCursorBitmap);
7692 pSur->Flags &= ~SFLAG_FORCELOAD;
7693 /* Do not store the surface's pointer because the application may release
7694 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7695 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7697 This->cursorTexture = pSur->glDescription.textureName;
7698 This->cursorWidth = pSur->currentDesc.Width;
7699 This->cursorHeight = pSur->currentDesc.Height;
7700 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7703 This->xHotSpot = XHotSpot;
7704 This->yHotSpot = YHotSpot;
7705 return WINED3D_OK;
7708 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7710 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7712 This->xScreenSpace = XScreenSpace;
7713 This->yScreenSpace = YScreenSpace;
7715 return;
7719 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7721 BOOL oldVisible = This->bCursorVisible;
7722 TRACE("(%p) : visible(%d)\n", This, bShow);
7724 if(This->cursorTexture)
7725 This->bCursorVisible = bShow;
7727 return oldVisible;
7730 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7732 TRACE("(%p) : state (%u)\n", This, This->state);
7733 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7734 switch (This->state) {
7735 case WINED3D_OK:
7736 return WINED3D_OK;
7737 case WINED3DERR_DEVICELOST:
7739 ResourceList *resourceList = This->resources;
7740 while (NULL != resourceList) {
7741 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7742 return WINED3DERR_DEVICENOTRESET;
7743 resourceList = resourceList->next;
7745 return WINED3DERR_DEVICELOST;
7747 case WINED3DERR_DRIVERINTERNALERROR:
7748 return WINED3DERR_DRIVERINTERNALERROR;
7751 /* Unknown state */
7752 return WINED3DERR_DRIVERINTERNALERROR;
7756 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7758 /** FIXME: Resource tracking needs to be done,
7759 * The closes we can do to this is set the priorities of all managed textures low
7760 * and then reset them.
7761 ***********************************************************/
7762 FIXME("(%p) : stub\n", This);
7763 return WINED3D_OK;
7766 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7768 /** FIXME: Resource trascking needs to be done.
7769 * in effect this pulls all non only default
7770 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7771 * and should clear down the context and set it up according to pPresentationParameters
7772 ***********************************************************/
7773 FIXME("(%p) : stub\n", This);
7774 return WINED3D_OK;
7777 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7779 /** FIXME: always true at the moment **/
7780 if(!bEnableDialogs) {
7781 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7783 return WINED3D_OK;
7787 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7789 TRACE("(%p) : pParameters %p\n", This, pParameters);
7791 *pParameters = This->createParms;
7792 return WINED3D_OK;
7795 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7796 IWineD3DSwapChain *swapchain;
7797 HRESULT hrc = WINED3D_OK;
7799 TRACE("Relaying to swapchain\n");
7801 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7802 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7803 IWineD3DSwapChain_Release(swapchain);
7805 return;
7808 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7809 IWineD3DSwapChain *swapchain;
7810 HRESULT hrc = WINED3D_OK;
7812 TRACE("Relaying to swapchain\n");
7814 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7815 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7816 IWineD3DSwapChain_Release(swapchain);
7818 return;
7822 /** ********************************************************
7823 * Notification functions
7824 ** ********************************************************/
7825 /** This function must be called in the release of a resource when ref == 0,
7826 * the contents of resource must still be correct,
7827 * any handels to other resource held by the caller must be closed
7828 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7829 *****************************************************/
7830 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7832 ResourceList* resourceList;
7834 TRACE("(%p) : resource %p\n", This, resource);
7835 #if 0
7836 EnterCriticalSection(&resourceStoreCriticalSection);
7837 #endif
7838 /* add a new texture to the frot of the linked list */
7839 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7840 resourceList->resource = resource;
7842 /* Get the old head */
7843 resourceList->next = This->resources;
7845 This->resources = resourceList;
7846 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7848 #if 0
7849 LeaveCriticalSection(&resourceStoreCriticalSection);
7850 #endif
7851 return;
7854 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7856 ResourceList* resourceList = NULL;
7857 ResourceList* previousResourceList = NULL;
7859 TRACE("(%p) : resource %p\n", This, resource);
7861 #if 0
7862 EnterCriticalSection(&resourceStoreCriticalSection);
7863 #endif
7864 resourceList = This->resources;
7866 while (resourceList != NULL) {
7867 if(resourceList->resource == resource) break;
7868 previousResourceList = resourceList;
7869 resourceList = resourceList->next;
7872 if (resourceList == NULL) {
7873 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7874 #if 0
7875 LeaveCriticalSection(&resourceStoreCriticalSection);
7876 #endif
7877 return;
7878 } else {
7879 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7881 /* make sure we don't leave a hole in the list */
7882 if (previousResourceList != NULL) {
7883 previousResourceList->next = resourceList->next;
7884 } else {
7885 This->resources = resourceList->next;
7888 #if 0
7889 LeaveCriticalSection(&resourceStoreCriticalSection);
7890 #endif
7891 return;
7895 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7897 int counter;
7899 TRACE("(%p) : resource %p\n", This, resource);
7900 switch(IWineD3DResource_GetType(resource)){
7901 case WINED3DRTYPE_SURFACE:
7902 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7903 break;
7904 case WINED3DRTYPE_TEXTURE:
7905 case WINED3DRTYPE_CUBETEXTURE:
7906 case WINED3DRTYPE_VOLUMETEXTURE:
7907 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7908 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7909 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7910 This->stateBlock->textures[counter] = NULL;
7912 if (This->updateStateBlock != This->stateBlock ){
7913 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7914 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7915 This->updateStateBlock->textures[counter] = NULL;
7919 break;
7920 case WINED3DRTYPE_VOLUME:
7921 /* TODO: nothing really? */
7922 break;
7923 case WINED3DRTYPE_VERTEXBUFFER:
7924 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7926 int streamNumber;
7927 TRACE("Cleaning up stream pointers\n");
7929 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7930 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7931 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7933 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7934 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7935 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7936 This->updateStateBlock->streamSource[streamNumber] = 0;
7937 /* Set changed flag? */
7940 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) */
7941 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7942 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7943 This->stateBlock->streamSource[streamNumber] = 0;
7946 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7947 else { /* This shouldn't happen */
7948 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7950 #endif
7954 break;
7955 case WINED3DRTYPE_INDEXBUFFER:
7956 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7957 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7958 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7959 This->updateStateBlock->pIndexData = NULL;
7962 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7963 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7964 This->stateBlock->pIndexData = NULL;
7968 break;
7969 default:
7970 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7971 break;
7975 /* Remove the resoruce from the resourceStore */
7976 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7978 TRACE("Resource released\n");
7982 /**********************************************************
7983 * IWineD3DDevice VTbl follows
7984 **********************************************************/
7986 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7988 /*** IUnknown methods ***/
7989 IWineD3DDeviceImpl_QueryInterface,
7990 IWineD3DDeviceImpl_AddRef,
7991 IWineD3DDeviceImpl_Release,
7992 /*** IWineD3DDevice methods ***/
7993 IWineD3DDeviceImpl_GetParent,
7994 /*** Creation methods**/
7995 IWineD3DDeviceImpl_CreateVertexBuffer,
7996 IWineD3DDeviceImpl_CreateIndexBuffer,
7997 IWineD3DDeviceImpl_CreateStateBlock,
7998 IWineD3DDeviceImpl_CreateSurface,
7999 IWineD3DDeviceImpl_CreateTexture,
8000 IWineD3DDeviceImpl_CreateVolumeTexture,
8001 IWineD3DDeviceImpl_CreateVolume,
8002 IWineD3DDeviceImpl_CreateCubeTexture,
8003 IWineD3DDeviceImpl_CreateQuery,
8004 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
8005 IWineD3DDeviceImpl_CreateVertexDeclaration,
8006 IWineD3DDeviceImpl_CreateVertexShader,
8007 IWineD3DDeviceImpl_CreatePixelShader,
8008 IWineD3DDeviceImpl_CreatePalette,
8009 /*** Odd functions **/
8010 IWineD3DDeviceImpl_Init3D,
8011 IWineD3DDeviceImpl_Uninit3D,
8012 IWineD3DDeviceImpl_SetFullscreen,
8013 IWineD3DDeviceImpl_EnumDisplayModes,
8014 IWineD3DDeviceImpl_EvictManagedResources,
8015 IWineD3DDeviceImpl_GetAvailableTextureMem,
8016 IWineD3DDeviceImpl_GetBackBuffer,
8017 IWineD3DDeviceImpl_GetCreationParameters,
8018 IWineD3DDeviceImpl_GetDeviceCaps,
8019 IWineD3DDeviceImpl_GetDirect3D,
8020 IWineD3DDeviceImpl_GetDisplayMode,
8021 IWineD3DDeviceImpl_SetDisplayMode,
8022 IWineD3DDeviceImpl_GetHWND,
8023 IWineD3DDeviceImpl_SetHWND,
8024 IWineD3DDeviceImpl_GetNumberOfSwapChains,
8025 IWineD3DDeviceImpl_GetRasterStatus,
8026 IWineD3DDeviceImpl_GetSwapChain,
8027 IWineD3DDeviceImpl_Reset,
8028 IWineD3DDeviceImpl_SetDialogBoxMode,
8029 IWineD3DDeviceImpl_SetCursorProperties,
8030 IWineD3DDeviceImpl_SetCursorPosition,
8031 IWineD3DDeviceImpl_ShowCursor,
8032 IWineD3DDeviceImpl_TestCooperativeLevel,
8033 /*** Getters and setters **/
8034 IWineD3DDeviceImpl_SetClipPlane,
8035 IWineD3DDeviceImpl_GetClipPlane,
8036 IWineD3DDeviceImpl_SetClipStatus,
8037 IWineD3DDeviceImpl_GetClipStatus,
8038 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8039 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8040 IWineD3DDeviceImpl_SetDepthStencilSurface,
8041 IWineD3DDeviceImpl_GetDepthStencilSurface,
8042 IWineD3DDeviceImpl_SetFVF,
8043 IWineD3DDeviceImpl_GetFVF,
8044 IWineD3DDeviceImpl_SetGammaRamp,
8045 IWineD3DDeviceImpl_GetGammaRamp,
8046 IWineD3DDeviceImpl_SetIndices,
8047 IWineD3DDeviceImpl_GetIndices,
8048 IWineD3DDeviceImpl_SetLight,
8049 IWineD3DDeviceImpl_GetLight,
8050 IWineD3DDeviceImpl_SetLightEnable,
8051 IWineD3DDeviceImpl_GetLightEnable,
8052 IWineD3DDeviceImpl_SetMaterial,
8053 IWineD3DDeviceImpl_GetMaterial,
8054 IWineD3DDeviceImpl_SetNPatchMode,
8055 IWineD3DDeviceImpl_GetNPatchMode,
8056 IWineD3DDeviceImpl_SetPaletteEntries,
8057 IWineD3DDeviceImpl_GetPaletteEntries,
8058 IWineD3DDeviceImpl_SetPixelShader,
8059 IWineD3DDeviceImpl_GetPixelShader,
8060 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8061 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8062 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8063 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8064 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8065 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8066 IWineD3DDeviceImpl_SetRenderState,
8067 IWineD3DDeviceImpl_GetRenderState,
8068 IWineD3DDeviceImpl_SetRenderTarget,
8069 IWineD3DDeviceImpl_GetRenderTarget,
8070 IWineD3DDeviceImpl_SetFrontBackBuffers,
8071 IWineD3DDeviceImpl_SetSamplerState,
8072 IWineD3DDeviceImpl_GetSamplerState,
8073 IWineD3DDeviceImpl_SetScissorRect,
8074 IWineD3DDeviceImpl_GetScissorRect,
8075 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8076 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8077 IWineD3DDeviceImpl_SetStreamSource,
8078 IWineD3DDeviceImpl_GetStreamSource,
8079 IWineD3DDeviceImpl_SetStreamSourceFreq,
8080 IWineD3DDeviceImpl_GetStreamSourceFreq,
8081 IWineD3DDeviceImpl_SetTexture,
8082 IWineD3DDeviceImpl_GetTexture,
8083 IWineD3DDeviceImpl_SetTextureStageState,
8084 IWineD3DDeviceImpl_GetTextureStageState,
8085 IWineD3DDeviceImpl_SetTransform,
8086 IWineD3DDeviceImpl_GetTransform,
8087 IWineD3DDeviceImpl_SetVertexDeclaration,
8088 IWineD3DDeviceImpl_GetVertexDeclaration,
8089 IWineD3DDeviceImpl_SetVertexShader,
8090 IWineD3DDeviceImpl_GetVertexShader,
8091 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8092 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8093 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8094 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8095 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8096 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8097 IWineD3DDeviceImpl_SetViewport,
8098 IWineD3DDeviceImpl_GetViewport,
8099 IWineD3DDeviceImpl_MultiplyTransform,
8100 IWineD3DDeviceImpl_ValidateDevice,
8101 IWineD3DDeviceImpl_ProcessVertices,
8102 /*** State block ***/
8103 IWineD3DDeviceImpl_BeginStateBlock,
8104 IWineD3DDeviceImpl_EndStateBlock,
8105 /*** Scene management ***/
8106 IWineD3DDeviceImpl_BeginScene,
8107 IWineD3DDeviceImpl_EndScene,
8108 IWineD3DDeviceImpl_Present,
8109 IWineD3DDeviceImpl_Clear,
8110 /*** Drawing ***/
8111 IWineD3DDeviceImpl_DrawPrimitive,
8112 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8113 IWineD3DDeviceImpl_DrawPrimitiveUP,
8114 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8115 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8116 IWineD3DDeviceImpl_DrawRectPatch,
8117 IWineD3DDeviceImpl_DrawTriPatch,
8118 IWineD3DDeviceImpl_DeletePatch,
8119 IWineD3DDeviceImpl_ColorFill,
8120 IWineD3DDeviceImpl_UpdateTexture,
8121 IWineD3DDeviceImpl_UpdateSurface,
8122 IWineD3DDeviceImpl_CopyRects,
8123 IWineD3DDeviceImpl_StretchRect,
8124 IWineD3DDeviceImpl_GetRenderTargetData,
8125 IWineD3DDeviceImpl_GetFrontBufferData,
8126 /*** Internal use IWineD3DDevice methods ***/
8127 IWineD3DDeviceImpl_SetupTextureStates,
8128 /*** object tracking ***/
8129 IWineD3DDeviceImpl_ResourceReleased
8133 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8134 WINED3DRS_ALPHABLENDENABLE ,
8135 WINED3DRS_ALPHAFUNC ,
8136 WINED3DRS_ALPHAREF ,
8137 WINED3DRS_ALPHATESTENABLE ,
8138 WINED3DRS_BLENDOP ,
8139 WINED3DRS_COLORWRITEENABLE ,
8140 WINED3DRS_DESTBLEND ,
8141 WINED3DRS_DITHERENABLE ,
8142 WINED3DRS_FILLMODE ,
8143 WINED3DRS_FOGDENSITY ,
8144 WINED3DRS_FOGEND ,
8145 WINED3DRS_FOGSTART ,
8146 WINED3DRS_LASTPIXEL ,
8147 WINED3DRS_SHADEMODE ,
8148 WINED3DRS_SRCBLEND ,
8149 WINED3DRS_STENCILENABLE ,
8150 WINED3DRS_STENCILFAIL ,
8151 WINED3DRS_STENCILFUNC ,
8152 WINED3DRS_STENCILMASK ,
8153 WINED3DRS_STENCILPASS ,
8154 WINED3DRS_STENCILREF ,
8155 WINED3DRS_STENCILWRITEMASK ,
8156 WINED3DRS_STENCILZFAIL ,
8157 WINED3DRS_TEXTUREFACTOR ,
8158 WINED3DRS_WRAP0 ,
8159 WINED3DRS_WRAP1 ,
8160 WINED3DRS_WRAP2 ,
8161 WINED3DRS_WRAP3 ,
8162 WINED3DRS_WRAP4 ,
8163 WINED3DRS_WRAP5 ,
8164 WINED3DRS_WRAP6 ,
8165 WINED3DRS_WRAP7 ,
8166 WINED3DRS_ZENABLE ,
8167 WINED3DRS_ZFUNC ,
8168 WINED3DRS_ZWRITEENABLE
8171 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8172 WINED3DTSS_ADDRESSW ,
8173 WINED3DTSS_ALPHAARG0 ,
8174 WINED3DTSS_ALPHAARG1 ,
8175 WINED3DTSS_ALPHAARG2 ,
8176 WINED3DTSS_ALPHAOP ,
8177 WINED3DTSS_BUMPENVLOFFSET ,
8178 WINED3DTSS_BUMPENVLSCALE ,
8179 WINED3DTSS_BUMPENVMAT00 ,
8180 WINED3DTSS_BUMPENVMAT01 ,
8181 WINED3DTSS_BUMPENVMAT10 ,
8182 WINED3DTSS_BUMPENVMAT11 ,
8183 WINED3DTSS_COLORARG0 ,
8184 WINED3DTSS_COLORARG1 ,
8185 WINED3DTSS_COLORARG2 ,
8186 WINED3DTSS_COLOROP ,
8187 WINED3DTSS_RESULTARG ,
8188 WINED3DTSS_TEXCOORDINDEX ,
8189 WINED3DTSS_TEXTURETRANSFORMFLAGS
8192 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8193 WINED3DSAMP_ADDRESSU ,
8194 WINED3DSAMP_ADDRESSV ,
8195 WINED3DSAMP_ADDRESSW ,
8196 WINED3DSAMP_BORDERCOLOR ,
8197 WINED3DSAMP_MAGFILTER ,
8198 WINED3DSAMP_MINFILTER ,
8199 WINED3DSAMP_MIPFILTER ,
8200 WINED3DSAMP_MIPMAPLODBIAS ,
8201 WINED3DSAMP_MAXMIPLEVEL ,
8202 WINED3DSAMP_MAXANISOTROPY ,
8203 WINED3DSAMP_SRGBTEXTURE ,
8204 WINED3DSAMP_ELEMENTINDEX
8207 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8208 WINED3DRS_AMBIENT ,
8209 WINED3DRS_AMBIENTMATERIALSOURCE ,
8210 WINED3DRS_CLIPPING ,
8211 WINED3DRS_CLIPPLANEENABLE ,
8212 WINED3DRS_COLORVERTEX ,
8213 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8214 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8215 WINED3DRS_FOGDENSITY ,
8216 WINED3DRS_FOGEND ,
8217 WINED3DRS_FOGSTART ,
8218 WINED3DRS_FOGTABLEMODE ,
8219 WINED3DRS_FOGVERTEXMODE ,
8220 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8221 WINED3DRS_LIGHTING ,
8222 WINED3DRS_LOCALVIEWER ,
8223 WINED3DRS_MULTISAMPLEANTIALIAS ,
8224 WINED3DRS_MULTISAMPLEMASK ,
8225 WINED3DRS_NORMALIZENORMALS ,
8226 WINED3DRS_PATCHEDGESTYLE ,
8227 WINED3DRS_POINTSCALE_A ,
8228 WINED3DRS_POINTSCALE_B ,
8229 WINED3DRS_POINTSCALE_C ,
8230 WINED3DRS_POINTSCALEENABLE ,
8231 WINED3DRS_POINTSIZE ,
8232 WINED3DRS_POINTSIZE_MAX ,
8233 WINED3DRS_POINTSIZE_MIN ,
8234 WINED3DRS_POINTSPRITEENABLE ,
8235 WINED3DRS_RANGEFOGENABLE ,
8236 WINED3DRS_SPECULARMATERIALSOURCE ,
8237 WINED3DRS_TWEENFACTOR ,
8238 WINED3DRS_VERTEXBLEND
8241 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8242 WINED3DTSS_TEXCOORDINDEX ,
8243 WINED3DTSS_TEXTURETRANSFORMFLAGS
8246 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8247 WINED3DSAMP_DMAPOFFSET