wined3d: Replace memset/memcpy routines on stateblock (fixes dynamic shader constants...
[wine/multimedia.git] / dlls / wined3d / device.c
blob6a86132a1ff3c9f8e283cea9c554ed744c983519
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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include <stdio.h>
28 #ifdef HAVE_FLOAT_H
29 # include <float.h>
30 #endif
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 D3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* Memory tracking and object counting */
74 static unsigned int emulated_textureram = 64*1024*1024;
76 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
77 /* enable pbuffer support for offscreen textures */
78 BOOL pbuffer_support = FALSE;
79 /* allocate one pbuffer per surface */
80 BOOL pbuffer_per_surface = FALSE;
82 /* static function declarations */
83 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
85 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
87 /* helper macros */
88 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
90 #define D3DCREATEOBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->wineD3DDevice = This; \
95 object->parent = parent; \
96 object->ref = 1; \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
117 *pp##type = NULL; \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
126 *pp##type = NULL; \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * Utility functions follow
148 **********************************************************/
149 /* Convert the D3DLIGHT properties into equivalent gl lights */
150 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
152 float quad_att;
153 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
157 glMatrixMode(GL_MODELVIEW);
158 glPushMatrix();
159 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
161 /* Diffuse: */
162 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
163 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
164 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
165 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
166 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
167 checkGLcall("glLightfv");
169 /* Specular */
170 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
171 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
172 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
173 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
174 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
175 checkGLcall("glLightfv");
177 /* Ambient */
178 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
179 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
180 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
181 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
182 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
183 checkGLcall("glLightfv");
185 /* Attenuation - Are these right? guessing... */
186 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
187 checkGLcall("glLightf");
188 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
189 checkGLcall("glLightf");
191 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
192 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
193 } else {
194 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
197 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
198 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
199 checkGLcall("glLightf");
201 switch (lightInfo->OriginalParms.Type) {
202 case D3DLIGHT_POINT:
203 /* Position */
204 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
205 checkGLcall("glLightfv");
206 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
207 checkGLcall("glLightf");
208 /* FIXME: Range */
209 break;
211 case D3DLIGHT_SPOT:
212 /* Position */
213 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
214 checkGLcall("glLightfv");
215 /* Direction */
216 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
217 checkGLcall("glLightfv");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
219 checkGLcall("glLightf");
220 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
221 checkGLcall("glLightf");
222 /* FIXME: Range */
223 break;
225 case D3DLIGHT_DIRECTIONAL:
226 /* Direction */
227 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
228 checkGLcall("glLightfv");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
230 checkGLcall("glLightf");
231 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
232 checkGLcall("glLightf");
233 break;
235 default:
236 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
239 /* Restore the modelview matrix */
240 glPopMatrix();
243 /**********************************************************
244 * GLSL helper functions follow
245 **********************************************************/
247 /** Attach a GLSL pixel or vertex shader object to the shader program */
248 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
252 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
253 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
254 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
255 checkGLcall("glAttachObjectARB");
259 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
260 * It sets the programId on the current StateBlock (because it should be called
261 * inside of the DrawPrimitive() part of the render loop).
263 * If a program for the given combination does not exist, create one, and store
264 * the program in the list. If it creates a program, it will link the given
265 * objects, too.
267 * We keep the shader programs around on a list because linking
268 * shader objects together is an expensive operation. It's much
269 * faster to loop through a list of pre-compiled & linked programs
270 * each time that the application sets a new pixel or vertex shader
271 * than it is to re-link them together at that time.
273 * The list will be deleted in IWineD3DDevice::Release().
275 void set_glsl_shader_program(IWineD3DDevice *iface) {
277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
278 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
279 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
280 struct glsl_shader_prog_link *curLink = NULL;
281 struct glsl_shader_prog_link *newLink = NULL;
282 struct list *ptr = NULL;
283 GLhandleARB programId = 0;
285 ptr = list_head( &This->glsl_shader_progs );
286 while (ptr) {
287 /* At least one program exists - see if it matches our ps/vs combination */
288 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
289 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
290 /* Existing Program found, use it */
291 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
292 curLink->programId);
293 This->stateBlock->shaderPrgId = curLink->programId;
294 return;
296 /* This isn't the entry we need - try the next one */
297 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* If we get to this point, then no matching program exists, so we create one */
301 programId = GL_EXTCALL(glCreateProgramObjectARB());
302 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
303 This->stateBlock->shaderPrgId = programId;
305 /* Allocate a new link for the list of programs */
306 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
307 newLink->programId = programId;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
311 int i;
312 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
313 char tmp_name[10];
315 TRACE("Attaching vertex shader to GLSL program\n");
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
322 * GLSL shaders.
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
332 newLink->vertexShader = vshader;
335 /* Attach GLSL pshader */
336 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
337 TRACE("Attaching pixel shader to GLSL program\n");
338 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
339 newLink->pixelShader = pshader;
342 /* Link the program */
343 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
344 GL_EXTCALL(glLinkProgramARB(programId));
345 print_glsl_info_log(&GLINFO_LOCATION, programId);
346 list_add_head( &This->glsl_shader_progs, &newLink->entry);
347 return;
350 /** Detach the GLSL pixel or vertex shader object from the shader program */
351 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
355 if (shaderObj != 0 && programId != 0) {
356 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
357 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
358 checkGLcall("glDetachObjectARB");
362 /** Delete a GLSL shader program */
363 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
367 if (obj != 0) {
368 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
369 GL_EXTCALL(glDeleteObjectARB(obj));
370 checkGLcall("glDeleteObjectARB");
374 /** Delete the list of linked programs this shader is associated with.
375 * Also at this point, check to see if there are any objects left attached
376 * to each GLSL program. If not, delete the GLSL program object.
377 * This will be run when a device is released. */
378 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
380 struct list *ptr = NULL;
381 struct glsl_shader_prog_link *curLink = NULL;
382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
384 int numAttached = 0;
385 int i;
386 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
387 (one pixel shader and one vertex shader at most) */
389 ptr = list_head( &This->glsl_shader_progs );
390 while (ptr) {
391 /* First, get the current item,
392 * save the link to the next pointer,
393 * detach and delete shader objects,
394 * then de-allocate the list item's memory */
395 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
396 ptr = list_next( &This->glsl_shader_progs, ptr );
398 /* See if this object is still attached to the program - it may have been detached already */
399 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
400 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
401 for (i = 0; i < numAttached; i++) {
402 detach_glsl_shader(iface, objList[i], curLink->programId);
405 delete_glsl_shader_program(iface, curLink->programId);
407 /* Free the memory for this list item */
408 HeapFree(GetProcessHeap(), 0, curLink);
413 /* Apply the current values to the specified texture stage */
414 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
416 float col[4];
418 union {
419 float f;
420 DWORD d;
421 } tmpvalue;
423 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
424 clamping, MIPLOD, etc. This will work for up to 16 samplers.
427 if (Sampler >= GL_LIMITS(sampler_stages)) {
428 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
429 return;
431 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
432 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
433 ENTER_GL();
434 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
435 checkGLcall("glActiveTextureARB");
436 LEAVE_GL();
437 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
438 } else if (Sampler > 0) {
439 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
440 return;
443 /* TODO: change this to a lookup table
444 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
445 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
446 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
447 especially when there are a number of groups of states. */
449 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
451 /* 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 */
452 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
453 /* these are the only two supported states that need to be applied */
454 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
455 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
456 #if 0 /* not supported at the moment */
457 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
458 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
459 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
460 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
461 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
462 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
463 APPLY_STATE(WINED3DTSS_RESULTARG);
464 APPLY_STATE(WINED3DTSS_CONSTANT);
465 #endif
466 /* a quick sanity check in case someone forgot to update this function */
467 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
468 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
470 #undef APPLY_STATE
472 /* apply any sampler states that always need applying */
473 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
474 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
475 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
476 GL_TEXTURE_LOD_BIAS_EXT,
477 tmpvalue.f);
478 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
481 /* Note the D3DRS value applies to all textures, but GL has one
482 * per texture, so apply it now ready to be used!
484 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
485 /* Set the default alpha blend color */
486 if (GL_SUPPORT(ARB_IMAGING)) {
487 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
488 checkGLcall("glBlendColor");
489 } else {
490 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
493 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
494 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
495 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
497 /* TODO: NV_POINT_SPRITE */
498 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
499 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
500 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
501 glDisable(GL_POINT_SMOOTH);
503 /* Centre the texture on the vertex */
504 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
505 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
507 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
508 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
509 checkGLcall("glTexEnvf(...)");
510 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
511 glEnable( GL_POINT_SPRITE_ARB );
512 checkGLcall("glEnable(...)");
513 } else {
514 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
515 glDisable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
520 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
523 /**********************************************************
524 * IUnknown parts follows
525 **********************************************************/
527 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
531 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
532 if (IsEqualGUID(riid, &IID_IUnknown)
533 || IsEqualGUID(riid, &IID_IWineD3DBase)
534 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
535 IUnknown_AddRef(iface);
536 *ppobj = This;
537 return S_OK;
539 *ppobj = NULL;
540 return E_NOINTERFACE;
543 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
545 ULONG refCount = InterlockedIncrement(&This->ref);
547 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
548 return refCount;
551 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
553 ULONG refCount = InterlockedDecrement(&This->ref);
555 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
557 if (!refCount) {
558 /* TODO: Clean up all the surfaces and textures! */
559 /* NOTE: You must release the parent if the object was created via a callback
560 ** ***************************/
562 /* Delete any GLSL shader programs that may exist */
563 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
564 wined3d_settings.ps_selected_mode == SHADER_GLSL)
565 delete_glsl_shader_list(iface);
567 /* Release the update stateblock */
568 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
569 if(This->updateStateBlock != This->stateBlock)
570 FIXME("(%p) Something's still holding the Update stateblock\n",This);
572 This->updateStateBlock = NULL;
573 { /* because were not doing proper internal refcounts releasing the primary state block
574 causes recursion with the extra checks in ResourceReleased, to avoid this we have
575 to set this->stateBlock = NULL; first */
576 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
577 This->stateBlock = NULL;
579 /* Release the stateblock */
580 if(IWineD3DStateBlock_Release(stateBlock) > 0){
581 FIXME("(%p) Something's still holding the Update stateblock\n",This);
585 if (This->resources != NULL ) {
586 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
587 dumpResources(This->resources);
591 IWineD3D_Release(This->wineD3D);
592 This->wineD3D = NULL;
593 HeapFree(GetProcessHeap(), 0, This);
594 TRACE("Freed device %p\n", This);
595 This = NULL;
597 return refCount;
600 /**********************************************************
601 * IWineD3DDevice implementation follows
602 **********************************************************/
603 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
605 *pParent = This->parent;
606 IUnknown_AddRef(This->parent);
607 return WINED3D_OK;
610 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
611 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
612 GLenum error, glUsage;
613 DWORD vboUsage = object->resource.usage;
614 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
615 WARN("Creating a vbo failed once, not trying again\n");
616 return;
619 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p\n", object);
621 ENTER_GL();
622 /* Make sure that the gl error is cleared. Do not use checkGLcall
623 * here because checkGLcall just prints a fixme and continues. However,
624 * if an error during VBO creation occurs we can fall back to non-vbo operation
625 * with full functionality(but performance loss)
627 while(glGetError() != GL_NO_ERROR);
629 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
630 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
631 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
632 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
633 * to check if the rhw and color values are in the correct format.
636 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
637 error = glGetError();
638 if(object->vbo == 0 || error != GL_NO_ERROR) {
639 WARN("Failed to create a VBO with error %d\n", error);
640 goto error;
643 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
644 error = glGetError();
645 if(error != GL_NO_ERROR) {
646 WARN("Failed to bind the VBO, error %d\n", error);
647 goto error;
650 /* Transformed vertices are horribly inflexible. If the app specifies an
651 * vertex buffer with transformed vertices in default pool without DYNAMIC
652 * usage assume DYNAMIC usage and print a warning. The app will have to update
653 * the vertices regularily for them to be useful
655 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
656 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
657 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
658 vboUsage |= WINED3DUSAGE_DYNAMIC;
661 /* Don't use static, because dx apps tend to update the buffer
662 * quite often even if they specify 0 usage
664 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
665 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
666 TRACE("Gl usage = GL_STREAM_DRAW\n");
667 glUsage = GL_STREAM_DRAW_ARB;
668 break;
669 case D3DUSAGE_WRITEONLY:
670 TRACE("Gl usage = GL_STATIC_DRAW\n");
671 glUsage = GL_DYNAMIC_DRAW_ARB;
672 break;
673 case D3DUSAGE_DYNAMIC:
674 TRACE("Gl usage = GL_STREAM_COPY\n");
675 glUsage = GL_STREAM_COPY_ARB;
676 break;
677 default:
678 TRACE("Gl usage = GL_STATIC_COPY\n");
679 glUsage = GL_DYNAMIC_COPY_ARB;
680 break;
683 /* Reserve memory for the buffer. The amount of data won't change
684 * so we are safe with calling glBufferData once with a NULL ptr and
685 * calling glBufferSubData on updates
687 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
688 error = glGetError();
689 if(error != GL_NO_ERROR) {
690 WARN("glBufferDataARB failed with error %d\n", error);
691 goto error;
694 LEAVE_GL();
696 return;
697 error:
698 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
699 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
700 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
701 object->vbo = 0;
702 object->Flags |= VBFLAG_VBOCREATEFAIL;
703 LEAVE_GL();
704 return;
707 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
708 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
709 IUnknown *parent) {
710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
711 IWineD3DVertexBufferImpl *object;
712 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
713 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
714 BOOL conv;
715 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
717 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
718 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
720 if(Size == 0) return WINED3DERR_INVALIDCALL;
722 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
723 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
725 object->fvf = FVF;
727 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
728 * drawStridedFast (half-life 2).
730 * Basically converting the vertices in the buffer is quite expensive, and observations
731 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
732 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
734 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
735 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
736 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
737 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
738 * dx7 apps.
739 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
740 * more. In this call we can convert dx7 buffers too.
742 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
743 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
744 (dxVersion > 7 || !conv) ) {
745 CreateVBO(object);
747 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
748 if(dxVersion == 7 && object->vbo) {
749 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
750 object->resource.allocatedMemory = NULL;
754 return WINED3D_OK;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
758 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
759 HANDLE *sharedHandle, IUnknown *parent) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DIndexBufferImpl *object;
762 TRACE("(%p) Creating index buffer\n", This);
764 /* Allocate the storage for the device */
765 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
767 /*TODO: use VBO's */
768 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
769 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
772 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
773 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
774 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
776 return WINED3D_OK;
779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DStateBlockImpl *object;
783 int i, j;
784 HRESULT temp_result;
786 D3DCREATEOBJECTINSTANCE(object, StateBlock)
787 object->blockType = Type;
789 /* Special case - Used during initialization to produce a placeholder stateblock
790 so other functions called can update a state block */
791 if (Type == WINED3DSBT_INIT) {
792 /* Don't bother increasing the reference count otherwise a device will never
793 be freed due to circular dependencies */
794 return WINED3D_OK;
797 temp_result = allocate_shader_constants(object);
798 if (WINED3D_OK != temp_result)
799 return temp_result;
801 /* Otherwise, might as well set the whole state block to the appropriate values */
802 if (This->stateBlock != NULL)
803 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
804 else
805 memset(object->streamFreq, 1, sizeof(object->streamFreq));
807 /* Reset the ref and type after kludging it */
808 object->wineD3DDevice = This;
809 object->ref = 1;
810 object->blockType = Type;
812 TRACE("Updating changed flags appropriate for type %d\n", Type);
814 if (Type == WINED3DSBT_ALL) {
816 TRACE("ALL => Pretend everything has changed\n");
817 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
819 } else if (Type == WINED3DSBT_PIXELSTATE) {
821 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
822 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
824 object->changed.pixelShader = TRUE;
826 /* Pixel Shader Constants */
827 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
828 object->changed.pixelShaderConstantsF[i] = TRUE;
829 for (i = 0; i < MAX_CONST_B; ++i)
830 object->changed.pixelShaderConstantsB[i] = TRUE;
831 for (i = 0; i < MAX_CONST_I; ++i)
832 object->changed.pixelShaderConstantsI[i] = TRUE;
834 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
835 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
837 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
838 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
839 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
842 for (j = 0 ; j < 16; j++) {
843 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
845 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
849 } else if (Type == WINED3DSBT_VERTEXSTATE) {
851 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
852 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
854 object->changed.vertexShader = TRUE;
856 /* Vertex Shader Constants */
857 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
858 object->changed.vertexShaderConstantsF[i] = TRUE;
859 for (i = 0; i < MAX_CONST_B; ++i)
860 object->changed.vertexShaderConstantsB[i] = TRUE;
861 for (i = 0; i < MAX_CONST_I; ++i)
862 object->changed.vertexShaderConstantsI[i] = TRUE;
864 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
865 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
867 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
868 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
869 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
872 for (j = 0 ; j < 16; j++){
873 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
874 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
878 /* Duplicate light chain */
880 PLIGHTINFOEL *src = NULL;
881 PLIGHTINFOEL *dst = NULL;
882 PLIGHTINFOEL *newEl = NULL;
883 src = This->stateBlock->lights;
884 object->lights = NULL;
887 while (src) {
888 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
889 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
890 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
891 newEl->prev = dst;
892 newEl->changed = TRUE;
893 newEl->enabledChanged = TRUE;
894 if (dst == NULL) {
895 object->lights = newEl;
896 } else {
897 dst->next = newEl;
899 dst = newEl;
900 src = src->next;
905 } else {
906 FIXME("Unrecognized state block type %d\n", Type);
909 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
910 return WINED3D_OK;
914 /* ************************************
915 MSDN:
916 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
918 Discard
919 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
921 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.
923 ******************************** */
925 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) {
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
928 unsigned int pow2Width, pow2Height;
929 unsigned int Size = 1;
930 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
931 TRACE("(%p) Create surface\n",This);
933 /** FIXME: Check ranges on the inputs are valid
934 * MSDN
935 * MultisampleQuality
936 * [in] Quality level. The valid range is between zero and one less than the level
937 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
938 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
939 * values of paired render targets, depth stencil surfaces, and the MultiSample type
940 * must all match.
941 *******************************/
945 * TODO: Discard MSDN
946 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
948 * If this flag is set, the contents of the depth stencil buffer will be
949 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
950 * with a different depth surface.
952 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
953 ***************************/
955 if(MultisampleQuality < 0) {
956 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
957 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
960 if(MultisampleQuality > 0) {
961 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
962 MultisampleQuality=0;
965 /** FIXME: Check that the format is supported
966 * by the device.
967 *******************************/
969 /* Non-power2 support */
971 /* Find the nearest pow2 match */
972 pow2Width = pow2Height = 1;
973 while (pow2Width < Width) pow2Width <<= 1;
974 while (pow2Height < Height) pow2Height <<= 1;
976 if (pow2Width > Width || pow2Height > Height) {
977 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
978 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
979 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
980 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
981 This, Width, Height);
982 return WINED3DERR_NOTAVAILABLE;
986 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
987 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
988 * space!
989 *********************************/
990 if (WINED3DFMT_UNKNOWN == Format) {
991 Size = 0;
992 } else if (Format == WINED3DFMT_DXT1) {
993 /* DXT1 is half byte per pixel */
994 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
996 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
997 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
998 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
999 } else {
1000 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1003 /** Create and initialise the surface resource **/
1004 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1005 /* "Standalone" surface */
1006 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1008 object->currentDesc.Width = Width;
1009 object->currentDesc.Height = Height;
1010 object->currentDesc.MultiSampleType = MultiSample;
1011 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1013 /* Setup some glformat defaults */
1014 object->glDescription.glFormat = tableEntry->glFormat;
1015 object->glDescription.glFormatInternal = tableEntry->glInternal;
1016 object->glDescription.glType = tableEntry->glType;
1018 object->glDescription.textureName = 0;
1019 object->glDescription.level = Level;
1020 object->glDescription.target = GL_TEXTURE_2D;
1022 /* Internal data */
1023 object->pow2Width = pow2Width;
1024 object->pow2Height = pow2Height;
1026 /* Flags */
1027 object->Flags = 0; /* We start without flags set */
1028 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1029 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1030 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1031 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1034 if (WINED3DFMT_UNKNOWN != Format) {
1035 object->bytesPerPixel = tableEntry->bpp;
1036 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1037 } else {
1038 object->bytesPerPixel = 0;
1039 object->pow2Size = 0;
1042 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1044 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1046 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1047 * this function is too deap to need to care about things like this.
1048 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1049 * ****************************************/
1050 switch(Pool) {
1051 case WINED3DPOOL_SCRATCH:
1052 if(Lockable == FALSE)
1053 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1054 which are mutually exclusive, setting lockable to true\n");
1055 Lockable = TRUE;
1056 break;
1057 case WINED3DPOOL_SYSTEMMEM:
1058 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1059 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1060 case WINED3DPOOL_MANAGED:
1061 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1062 Usage of DYNAMIC which are mutually exclusive, not doing \
1063 anything just telling you.\n");
1064 break;
1065 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1066 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1067 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1068 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1069 break;
1070 default:
1071 FIXME("(%p) Unknown pool %d\n", This, Pool);
1072 break;
1075 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1076 FIXME("Trying to create a render target that isn't in the default pool\n");
1079 /* mark the texture as dirty so that it get's loaded first time around*/
1080 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1081 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1082 This, Width, Height, Format, debug_d3dformat(Format),
1083 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1085 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1086 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1087 This->ddraw_primary = (IWineD3DSurface *) object;
1089 /* Look at the implementation and set the correct Vtable */
1090 switch(Impl) {
1091 case SURFACE_OPENGL:
1092 /* Nothing to do, it's set already */
1093 break;
1095 case SURFACE_GDI:
1096 object->lpVtbl = &IWineGDISurface_Vtbl;
1097 break;
1099 default:
1100 /* To be sure to catch this */
1101 ERR("Unknown requested surface implementation %d!\n", Impl);
1102 IWineD3DSurface_Release((IWineD3DSurface *) object);
1103 return WINED3DERR_INVALIDCALL;
1106 /* Call the private setup routine */
1107 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1111 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1112 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1113 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1114 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1117 IWineD3DTextureImpl *object;
1118 unsigned int i;
1119 UINT tmpW;
1120 UINT tmpH;
1121 HRESULT hr;
1122 unsigned int pow2Width = Width;
1123 unsigned int pow2Height = Height;
1126 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1128 /* TODO: It should only be possible to create textures for formats
1129 that are reported as supported */
1130 if (WINED3DFMT_UNKNOWN >= Format) {
1131 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1132 return WINED3DERR_INVALIDCALL;
1135 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1136 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 object->width = Width;
1138 object->height = Height;
1140 /** Non-power2 support **/
1141 /* Find the nearest pow2 match */
1142 pow2Width = pow2Height = 1;
1143 while (pow2Width < Width) pow2Width <<= 1;
1144 while (pow2Height < Height) pow2Height <<= 1;
1146 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1147 /* Precalculated scaling for 'faked' non power of two texture coords */
1148 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1149 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1150 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1152 /* Calculate levels for mip mapping */
1153 if (Levels == 0) {
1154 TRACE("calculating levels %d\n", object->baseTexture.levels);
1155 object->baseTexture.levels++;
1156 tmpW = Width;
1157 tmpH = Height;
1158 while (tmpW > 1 || tmpH > 1) {
1159 tmpW = max(1, tmpW >> 1);
1160 tmpH = max(1, tmpH >> 1);
1161 object->baseTexture.levels++;
1163 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1166 /* Generate all the surfaces */
1167 tmpW = Width;
1168 tmpH = Height;
1169 for (i = 0; i < object->baseTexture.levels; i++)
1171 /* use the callback to create the texture surface */
1172 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1173 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1174 FIXME("Failed to create surface %p\n", object);
1175 /* clean up */
1176 object->surfaces[i] = NULL;
1177 IWineD3DTexture_Release((IWineD3DTexture *)object);
1179 *ppTexture = NULL;
1180 return hr;
1183 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1184 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1185 /* calculate the next mipmap level */
1186 tmpW = max(1, tmpW >> 1);
1187 tmpH = max(1, tmpH >> 1);
1190 TRACE("(%p) : Created texture %p\n", This, object);
1191 return WINED3D_OK;
1194 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1195 UINT Width, UINT Height, UINT Depth,
1196 UINT Levels, DWORD Usage,
1197 WINED3DFORMAT Format, WINED3DPOOL Pool,
1198 IWineD3DVolumeTexture **ppVolumeTexture,
1199 HANDLE *pSharedHandle, IUnknown *parent,
1200 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1203 IWineD3DVolumeTextureImpl *object;
1204 unsigned int i;
1205 UINT tmpW;
1206 UINT tmpH;
1207 UINT tmpD;
1209 /* TODO: It should only be possible to create textures for formats
1210 that are reported as supported */
1211 if (WINED3DFMT_UNKNOWN >= Format) {
1212 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1213 return WINED3DERR_INVALIDCALL;
1216 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1217 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1219 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1220 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1222 object->width = Width;
1223 object->height = Height;
1224 object->depth = Depth;
1226 /* Calculate levels for mip mapping */
1227 if (Levels == 0) {
1228 object->baseTexture.levels++;
1229 tmpW = Width;
1230 tmpH = Height;
1231 tmpD = Depth;
1232 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1233 tmpW = max(1, tmpW >> 1);
1234 tmpH = max(1, tmpH >> 1);
1235 tmpD = max(1, tmpD >> 1);
1236 object->baseTexture.levels++;
1238 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1241 /* Generate all the surfaces */
1242 tmpW = Width;
1243 tmpH = Height;
1244 tmpD = Depth;
1246 for (i = 0; i < object->baseTexture.levels; i++)
1248 /* Create the volume */
1249 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1250 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1252 /* Set it's container to this object */
1253 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1255 /* calcualte the next mipmap level */
1256 tmpW = max(1, tmpW >> 1);
1257 tmpH = max(1, tmpH >> 1);
1258 tmpD = max(1, tmpD >> 1);
1261 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1262 TRACE("(%p) : Created volume texture %p\n", This, object);
1263 return WINED3D_OK;
1266 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1267 UINT Width, UINT Height, UINT Depth,
1268 DWORD Usage,
1269 WINED3DFORMAT Format, WINED3DPOOL Pool,
1270 IWineD3DVolume** ppVolume,
1271 HANDLE* pSharedHandle, IUnknown *parent) {
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1275 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1277 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1279 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1280 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1282 object->currentDesc.Width = Width;
1283 object->currentDesc.Height = Height;
1284 object->currentDesc.Depth = Depth;
1285 object->bytesPerPixel = formatDesc->bpp;
1287 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1288 object->lockable = TRUE;
1289 object->locked = FALSE;
1290 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1291 object->dirty = TRUE;
1293 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1297 UINT Levels, DWORD Usage,
1298 WINED3DFORMAT Format, WINED3DPOOL Pool,
1299 IWineD3DCubeTexture **ppCubeTexture,
1300 HANDLE *pSharedHandle, IUnknown *parent,
1301 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1305 unsigned int i, j;
1306 UINT tmpW;
1307 HRESULT hr;
1308 unsigned int pow2EdgeLength = EdgeLength;
1310 /* TODO: It should only be possible to create textures for formats
1311 that are reported as supported */
1312 if (WINED3DFMT_UNKNOWN >= Format) {
1313 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1314 return WINED3DERR_INVALIDCALL;
1317 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1318 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1320 TRACE("(%p) Create Cube Texture\n", This);
1322 /** Non-power2 support **/
1324 /* Find the nearest pow2 match */
1325 pow2EdgeLength = 1;
1326 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1328 object->edgeLength = EdgeLength;
1329 /* TODO: support for native non-power 2 */
1330 /* Precalculated scaling for 'faked' non power of two texture coords */
1331 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1333 /* Calculate levels for mip mapping */
1334 if (Levels == 0) {
1335 object->baseTexture.levels++;
1336 tmpW = EdgeLength;
1337 while (tmpW > 1) {
1338 tmpW = max(1, tmpW >> 1);
1339 object->baseTexture.levels++;
1341 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1344 /* Generate all the surfaces */
1345 tmpW = EdgeLength;
1346 for (i = 0; i < object->baseTexture.levels; i++) {
1348 /* Create the 6 faces */
1349 for (j = 0; j < 6; j++) {
1351 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1352 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1354 if(hr!= WINED3D_OK) {
1355 /* clean up */
1356 int k;
1357 int l;
1358 for (l = 0; l < j; l++) {
1359 IWineD3DSurface_Release(object->surfaces[j][i]);
1361 for (k = 0; k < i; k++) {
1362 for (l = 0; l < 6; l++) {
1363 IWineD3DSurface_Release(object->surfaces[l][j]);
1367 FIXME("(%p) Failed to create surface\n",object);
1368 HeapFree(GetProcessHeap(),0,object);
1369 *ppCubeTexture = NULL;
1370 return hr;
1372 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1373 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1375 tmpW = max(1, tmpW >> 1);
1378 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1379 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1380 return WINED3D_OK;
1383 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1385 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1387 if (NULL == ppQuery) {
1388 /* Just a check to see if we support this type of query */
1389 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1390 switch(Type) {
1391 case WINED3DQUERYTYPE_OCCLUSION:
1392 TRACE("(%p) occlusion query\n", This);
1393 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1394 hr = WINED3D_OK;
1395 else
1396 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1397 break;
1398 case WINED3DQUERYTYPE_VCACHE:
1399 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1400 case WINED3DQUERYTYPE_VERTEXSTATS:
1401 case WINED3DQUERYTYPE_EVENT:
1402 case WINED3DQUERYTYPE_TIMESTAMP:
1403 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1404 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1405 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1406 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1407 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1408 case WINED3DQUERYTYPE_PIXELTIMINGS:
1409 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1410 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1411 default:
1412 FIXME("(%p) Unhandled query type %d\n", This, Type);
1414 return hr;
1417 D3DCREATEOBJECTINSTANCE(object, Query)
1418 object->type = Type;
1419 /* allocated the 'extended' data based on the type of query requested */
1420 switch(Type){
1421 case D3DQUERYTYPE_OCCLUSION:
1422 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1423 TRACE("(%p) Allocating data for an occlusion query\n", This);
1424 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1425 break;
1427 case D3DQUERYTYPE_VCACHE:
1428 case D3DQUERYTYPE_RESOURCEMANAGER:
1429 case D3DQUERYTYPE_VERTEXSTATS:
1430 case D3DQUERYTYPE_EVENT:
1431 case D3DQUERYTYPE_TIMESTAMP:
1432 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1433 case D3DQUERYTYPE_TIMESTAMPFREQ:
1434 case D3DQUERYTYPE_PIPELINETIMINGS:
1435 case D3DQUERYTYPE_INTERFACETIMINGS:
1436 case D3DQUERYTYPE_VERTEXTIMINGS:
1437 case D3DQUERYTYPE_PIXELTIMINGS:
1438 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1439 case D3DQUERYTYPE_CACHEUTILIZATION:
1440 default:
1441 object->extendedData = 0;
1442 FIXME("(%p) Unhandled query type %d\n",This , Type);
1444 TRACE("(%p) : Created Query %p\n", This, object);
1445 return WINED3D_OK;
1448 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1449 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1450 IUnknown* parent,
1451 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1452 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1455 HDC hDc;
1456 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1457 int num;
1458 XVisualInfo template;
1459 GLXContext oldContext;
1460 Drawable oldDrawable;
1461 HRESULT hr = WINED3D_OK;
1463 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1465 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1466 * does a device hold a reference to a swap chain giving them a lifetime of the device
1467 * or does the swap chain notify the device of its destruction.
1468 *******************************/
1470 /* Check the params */
1471 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1472 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1473 return WINED3DERR_INVALIDCALL;
1474 } else if (*pPresentationParameters->BackBufferCount > 1) {
1475 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");
1478 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1480 /*********************
1481 * Lookup the window Handle and the relating X window handle
1482 ********************/
1484 /* Setup hwnd we are using, plus which display this equates to */
1485 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1486 if (!object->win_handle) {
1487 object->win_handle = This->createParms.hFocusWindow;
1490 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1491 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1492 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1493 return WINED3DERR_NOTAVAILABLE;
1495 hDc = GetDC(object->win_handle);
1496 object->display = get_display(hDc);
1497 ReleaseDC(object->win_handle, hDc);
1498 TRACE("Using a display of %p %p\n", object->display, hDc);
1500 if (NULL == object->display || NULL == hDc) {
1501 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1502 return WINED3DERR_NOTAVAILABLE;
1505 if (object->win == 0) {
1506 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1507 return WINED3DERR_NOTAVAILABLE;
1510 * Create an opengl context for the display visual
1511 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1512 * use different properties after that point in time. FIXME: How to handle when requested format
1513 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1514 * it chooses is identical to the one already being used!
1515 **********************************/
1517 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1518 ENTER_GL();
1520 /* Create a new context for this swapchain */
1521 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1522 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1523 (or the best possible if none is requested) */
1524 TRACE("Found x visual ID : %ld\n", template.visualid);
1526 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1527 if (NULL == object->visInfo) {
1528 ERR("cannot really get XVisual\n");
1529 LEAVE_GL();
1530 return WINED3DERR_NOTAVAILABLE;
1531 } else {
1532 int n, value;
1533 /* Write out some debug info about the visual/s */
1534 TRACE("Using x visual ID : %ld\n", template.visualid);
1535 TRACE(" visual info: %p\n", object->visInfo);
1536 TRACE(" num items : %d\n", num);
1537 for (n = 0;n < num; n++) {
1538 TRACE("=====item=====: %d\n", n + 1);
1539 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1540 TRACE(" screen : %d\n", object->visInfo[n].screen);
1541 TRACE(" depth : %u\n", object->visInfo[n].depth);
1542 TRACE(" class : %d\n", object->visInfo[n].class);
1543 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1544 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1545 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1546 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1547 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1548 /* log some extra glx info */
1549 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1550 TRACE(" gl_aux_buffers : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1552 TRACE(" gl_buffer_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1554 TRACE(" gl_red_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1556 TRACE(" gl_green_size : %d\n", value);
1557 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1558 TRACE(" gl_blue_size : %d\n", value);
1559 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1560 TRACE(" gl_alpha_size : %d\n", value);
1561 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1562 TRACE(" gl_depth_size : %d\n", value);
1563 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1564 TRACE(" gl_stencil_size : %d\n", value);
1566 /* Now choose a simila visual ID*/
1568 #ifdef USE_CONTEXT_MANAGER
1570 /** TODO: use a context mamager **/
1571 #endif
1574 IWineD3DSwapChain *implSwapChain;
1575 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1576 /* The first time around we create the context that is shared with all other swapchains and render targets */
1577 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1578 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1579 } else {
1581 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1582 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1583 /* and create a new context with the implicit swapchains context as the shared context */
1584 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1585 IWineD3DSwapChain_Release(implSwapChain);
1589 /* Cleanup */
1590 XFree(object->visInfo);
1591 object->visInfo = NULL;
1593 LEAVE_GL();
1595 if (!object->glCtx) {
1596 ERR("Failed to create GLX context\n");
1597 return WINED3DERR_NOTAVAILABLE;
1598 } else {
1599 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1600 object->win_handle, object->glCtx, object->win, object->visInfo);
1603 /*********************
1604 * Windowed / Fullscreen
1605 *******************/
1608 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1609 * so we should really check to see if there is a fullscreen swapchain already
1610 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1611 **************************************/
1613 if (!*(pPresentationParameters->Windowed)) {
1615 DEVMODEW devmode;
1616 HDC hdc;
1617 int bpp = 0;
1619 /* Get info on the current display setup */
1620 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1621 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1622 DeleteDC(hdc);
1624 /* Change the display settings */
1625 memset(&devmode, 0, sizeof(DEVMODEW));
1626 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1627 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1628 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1629 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1630 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1631 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1633 /* Make popup window */
1634 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1635 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1636 *(pPresentationParameters->BackBufferWidth),
1637 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1639 /* For GetDisplayMode */
1640 This->ddraw_width = devmode.dmPelsWidth;
1641 This->ddraw_height = devmode.dmPelsHeight;
1642 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1646 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1647 * then the corresponding dimension of the client area of the hDeviceWindow
1648 * (or the focus window, if hDeviceWindow is NULL) is taken.
1649 **********************/
1651 if (*(pPresentationParameters->Windowed) &&
1652 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1653 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1655 RECT Rect;
1656 GetClientRect(object->win_handle, &Rect);
1658 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1659 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1660 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1662 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1663 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1664 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1668 /*********************
1669 * finish off parameter initialization
1670 *******************/
1672 /* Put the correct figures in the presentation parameters */
1673 TRACE("Coppying accross presentaion paraneters\n");
1674 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1675 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1676 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1677 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1678 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1679 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1680 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1681 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1682 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1683 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1684 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1685 object->presentParms.Flags = *(pPresentationParameters->Flags);
1686 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1687 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1690 /*********************
1691 * Create the back, front and stencil buffers
1692 *******************/
1694 TRACE("calling rendertarget CB\n");
1695 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1696 object->presentParms.BackBufferWidth,
1697 object->presentParms.BackBufferHeight,
1698 object->presentParms.BackBufferFormat,
1699 object->presentParms.MultiSampleType,
1700 object->presentParms.MultiSampleQuality,
1701 TRUE /* Lockable */,
1702 &object->frontBuffer,
1703 NULL /* pShared (always null)*/);
1704 if (object->frontBuffer != NULL)
1705 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1707 if(object->presentParms.BackBufferCount > 0) {
1708 int i;
1710 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1711 if(!object->backBuffer) {
1712 ERR("Out of memory\n");
1714 if (object->frontBuffer) {
1715 IUnknown *bufferParent;
1716 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1717 IUnknown_Release(bufferParent); /* once for the get parent */
1718 if (IUnknown_Release(bufferParent) > 0) {
1719 FIXME("(%p) Something's still holding the front buffer\n",This);
1722 HeapFree(GetProcessHeap(), 0, object);
1723 return E_OUTOFMEMORY;
1726 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1727 TRACE("calling rendertarget CB\n");
1728 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1729 object->presentParms.BackBufferWidth,
1730 object->presentParms.BackBufferHeight,
1731 object->presentParms.BackBufferFormat,
1732 object->presentParms.MultiSampleType,
1733 object->presentParms.MultiSampleQuality,
1734 TRUE /* Lockable */,
1735 &object->backBuffer[i],
1736 NULL /* pShared (always null)*/);
1737 if(hr == WINED3D_OK && object->backBuffer[i]) {
1738 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1739 } else {
1740 break;
1743 } else {
1744 object->backBuffer = NULL;
1747 if (object->backBuffer != NULL) {
1748 ENTER_GL();
1749 glDrawBuffer(GL_BACK);
1750 checkGLcall("glDrawBuffer(GL_BACK)");
1751 LEAVE_GL();
1752 } else {
1753 /* Single buffering - draw to front buffer */
1754 ENTER_GL();
1755 glDrawBuffer(GL_FRONT);
1756 checkGLcall("glDrawBuffer(GL_FRONT)");
1757 LEAVE_GL();
1760 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1761 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1762 TRACE("Creating depth stencil buffer\n");
1763 if (This->depthStencilBuffer == NULL ) {
1764 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1765 object->presentParms.BackBufferWidth,
1766 object->presentParms.BackBufferHeight,
1767 object->presentParms.AutoDepthStencilFormat,
1768 object->presentParms.MultiSampleType,
1769 object->presentParms.MultiSampleQuality,
1770 FALSE /* FIXME: Discard */,
1771 &This->depthStencilBuffer,
1772 NULL /* pShared (always null)*/ );
1773 if (This->depthStencilBuffer != NULL)
1774 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1777 /** TODO: A check on width, height and multisample types
1778 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1779 ****************************/
1780 object->wantsDepthStencilBuffer = TRUE;
1781 } else {
1782 object->wantsDepthStencilBuffer = FALSE;
1785 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1788 /*********************
1789 * init the default renderTarget management
1790 *******************/
1791 object->drawable = object->win;
1792 object->render_ctx = object->glCtx;
1794 if (hr == WINED3D_OK) {
1795 /*********************
1796 * Setup some defaults and clear down the buffers
1797 *******************/
1798 ENTER_GL();
1799 /** save current context and drawable **/
1800 oldContext = glXGetCurrentContext();
1801 oldDrawable = glXGetCurrentDrawable();
1803 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1804 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1805 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1807 checkGLcall("glXMakeCurrent");
1809 TRACE("Setting up the screen\n");
1810 /* Clear the screen */
1811 glClearColor(1.0, 0.0, 0.0, 0.0);
1812 checkGLcall("glClearColor");
1813 glClearIndex(0);
1814 glClearDepth(1);
1815 glClearStencil(0xffff);
1817 checkGLcall("glClear");
1819 glColor3f(1.0, 1.0, 1.0);
1820 checkGLcall("glColor3f");
1822 glEnable(GL_LIGHTING);
1823 checkGLcall("glEnable");
1825 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1826 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1828 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1829 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1831 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1832 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1834 /* switch back to the original context (if there was one)*/
1835 if (This->swapchains) {
1836 /** TODO: restore the context and drawable **/
1837 glXMakeCurrent(object->display, oldDrawable, oldContext);
1840 LEAVE_GL();
1842 TRACE("Set swapchain to %p\n", object);
1843 } else { /* something went wrong so clean up */
1844 IUnknown* bufferParent;
1845 if (object->frontBuffer) {
1847 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1848 IUnknown_Release(bufferParent); /* once for the get parent */
1849 if (IUnknown_Release(bufferParent) > 0) {
1850 FIXME("(%p) Something's still holding the front buffer\n",This);
1853 if (object->backBuffer) {
1854 int i;
1855 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1856 if(object->backBuffer[i]) {
1857 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1858 IUnknown_Release(bufferParent); /* once for the get parent */
1859 if (IUnknown_Release(bufferParent) > 0) {
1860 FIXME("(%p) Something's still holding the back buffer\n",This);
1864 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1865 object->backBuffer = NULL;
1867 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1868 /* Clean up the context */
1869 /* check that we are the current context first (we shouldn't be though!) */
1870 if (object->glCtx != 0) {
1871 if(glXGetCurrentContext() == object->glCtx) {
1872 glXMakeCurrent(object->display, None, NULL);
1874 glXDestroyContext(object->display, object->glCtx);
1876 HeapFree(GetProcessHeap(), 0, object);
1880 return hr;
1883 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1884 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1886 TRACE("(%p)\n", This);
1888 return This->NumberOfSwapChains;
1891 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1895 if(iSwapChain < This->NumberOfSwapChains) {
1896 *pSwapChain = This->swapchains[iSwapChain];
1897 IWineD3DSwapChain_AddRef(*pSwapChain);
1898 TRACE("(%p) returning %p\n", This, *pSwapChain);
1899 return WINED3D_OK;
1900 } else {
1901 TRACE("Swapchain out of range\n");
1902 *pSwapChain = NULL;
1903 return WINED3DERR_INVALIDCALL;
1907 /*****
1908 * Vertex Declaration
1909 *****/
1910 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1912 IWineD3DVertexDeclarationImpl *object = NULL;
1913 HRESULT hr = WINED3D_OK;
1914 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1915 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1916 object->allFVF = 0;
1918 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1920 return hr;
1923 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1926 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1927 HRESULT hr = WINED3D_OK;
1928 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1929 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1931 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1933 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1934 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1935 if (pDeclaration != NULL) {
1936 IWineD3DVertexDeclaration *vertexDeclaration;
1937 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1938 if (WINED3D_OK == hr) {
1939 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1940 object->vertexDeclaration = vertexDeclaration;
1941 } else {
1942 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1943 IWineD3DVertexShader_Release(*ppVertexShader);
1944 return WINED3DERR_INVALIDCALL;
1948 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1950 if (WINED3D_OK != hr) {
1951 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1952 IWineD3DVertexShader_Release(*ppVertexShader);
1953 return WINED3DERR_INVALIDCALL;
1956 #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. */
1957 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1958 /* Foo */
1959 } else {
1960 /* Bar */
1963 #endif
1965 return WINED3D_OK;
1968 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1970 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1971 HRESULT hr = WINED3D_OK;
1973 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1974 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1975 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1976 if (WINED3D_OK == hr) {
1977 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1978 } else {
1979 WARN("(%p) : Failed to create pixel shader\n", This);
1982 return hr;
1985 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 IWineD3DPaletteImpl *object;
1988 HRESULT hr;
1989 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1991 /* Create the new object */
1992 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1993 if(!object) {
1994 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1995 return E_OUTOFMEMORY;
1998 object->lpVtbl = &IWineD3DPalette_Vtbl;
1999 object->ref = 1;
2000 object->Flags = Flags;
2001 object->parent = Parent;
2002 object->wineD3DDevice = This;
2003 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2005 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2007 if(!object->hpal) {
2008 HeapFree( GetProcessHeap(), 0, object);
2009 return E_OUTOFMEMORY;
2012 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2013 if(FAILED(hr)) {
2014 IWineD3DPalette_Release((IWineD3DPalette *) object);
2015 return hr;
2018 *Palette = (IWineD3DPalette *) object;
2020 return WINED3D_OK;
2023 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2025 IWineD3DSwapChainImpl *swapchain;
2027 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2028 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2030 /* TODO: Test if OpenGL is compiled in and loaded */
2032 /* Setup the implicit swapchain */
2033 TRACE("Creating implicit swapchain\n");
2034 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2035 WARN("Failed to create implicit swapchain\n");
2036 return WINED3DERR_INVALIDCALL;
2039 This->NumberOfSwapChains = 1;
2040 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2041 if(!This->swapchains) {
2042 ERR("Out of memory!\n");
2043 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2044 return E_OUTOFMEMORY;
2046 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2048 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2049 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2050 This->renderTarget = swapchain->backBuffer[0];
2052 else {
2053 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2054 This->renderTarget = swapchain->frontBuffer;
2056 IWineD3DSurface_AddRef(This->renderTarget);
2057 /* Depth Stencil support */
2058 This->stencilBufferTarget = This->depthStencilBuffer;
2059 if (NULL != This->stencilBufferTarget) {
2060 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2063 /* Set up some starting GL setup */
2064 ENTER_GL();
2066 * Initialize openGL extension related variables
2067 * with Default values
2070 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2071 /* Setup all the devices defaults */
2072 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2073 #if 0
2074 IWineD3DImpl_CheckGraphicsMemory();
2075 #endif
2076 LEAVE_GL();
2078 /* Initialize our list of GLSL programs */
2079 list_init(&This->glsl_shader_progs);
2081 { /* Set a default viewport */
2082 D3DVIEWPORT9 vp;
2083 vp.X = 0;
2084 vp.Y = 0;
2085 vp.Width = *(pPresentationParameters->BackBufferWidth);
2086 vp.Height = *(pPresentationParameters->BackBufferHeight);
2087 vp.MinZ = 0.0f;
2088 vp.MaxZ = 1.0f;
2089 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2092 /* Initialize the current view state */
2093 This->modelview_valid = 1;
2094 This->proj_valid = 0;
2095 This->view_ident = 1;
2096 This->last_was_rhw = 0;
2097 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2098 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2100 /* Clear the screen */
2101 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2103 This->d3d_initialized = TRUE;
2104 return WINED3D_OK;
2107 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2109 int sampler;
2110 IUnknown* stencilBufferParent;
2111 IUnknown* swapChainParent;
2112 uint i;
2113 TRACE("(%p)\n", This);
2115 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2117 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2118 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2121 /* Release the buffers (with sanity checks)*/
2122 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2123 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2124 if(This->depthStencilBuffer != This->stencilBufferTarget)
2125 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2127 This->stencilBufferTarget = NULL;
2129 TRACE("Releasing the render target at %p\n", This->renderTarget);
2130 if(IWineD3DSurface_Release(This->renderTarget) >0){
2131 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2133 TRACE("Setting rendertarget to NULL\n");
2134 This->renderTarget = NULL;
2136 if (This->depthStencilBuffer) {
2137 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2138 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2139 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2140 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2142 This->depthStencilBuffer = NULL;
2145 for(i=0; i < This->NumberOfSwapChains; i++) {
2146 TRACE("Releasing the implicit swapchain %d\n", i);
2147 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2148 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2149 IUnknown_Release(swapChainParent); /* once for the get parent */
2150 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2151 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2155 HeapFree(GetProcessHeap(), 0, This->swapchains);
2156 This->swapchains = NULL;
2157 This->NumberOfSwapChains = 0;
2159 This->d3d_initialized = FALSE;
2160 return WINED3D_OK;
2163 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2166 DEVMODEW DevModeW;
2167 int i;
2168 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2170 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2172 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2173 /* Ignore some modes if a description was passed */
2174 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2175 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2176 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2178 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2180 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2181 return D3D_OK;
2184 return D3D_OK;
2187 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2188 DEVMODEW devmode;
2189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2190 LONG ret;
2191 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2193 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2195 /* Resize the screen even without a window:
2196 * The app could have unset it with SetCooperativeLevel, but not called
2197 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2198 * but we don't have any hwnd
2201 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2202 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2203 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2204 devmode.dmPelsWidth = pMode->Width;
2205 devmode.dmPelsHeight = pMode->Height;
2207 devmode.dmDisplayFrequency = pMode->RefreshRate;
2208 if (pMode->RefreshRate != 0) {
2209 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2212 /* Only change the mode if necessary */
2213 if( (This->ddraw_width == pMode->Width) &&
2214 (This->ddraw_height == pMode->Height) &&
2215 (This->ddraw_format == pMode->Format) &&
2216 (pMode->RefreshRate == 0) ) {
2217 return D3D_OK;
2220 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2221 if (ret != DISP_CHANGE_SUCCESSFUL) {
2222 if(devmode.dmDisplayFrequency != 0) {
2223 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2224 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2225 devmode.dmDisplayFrequency = 0;
2226 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2228 if(ret != DISP_CHANGE_SUCCESSFUL) {
2229 return DDERR_INVALIDMODE;
2233 /* Store the new values */
2234 This->ddraw_width = pMode->Width;
2235 This->ddraw_height = pMode->Height;
2236 This->ddraw_format = pMode->Format;
2238 /* Only do this with a window of course */
2239 if(This->ddraw_window)
2240 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2242 return WINED3D_OK;
2245 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2247 *ppD3D= This->wineD3D;
2248 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2249 IWineD3D_AddRef(*ppD3D);
2250 return WINED3D_OK;
2253 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2254 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2255 * Into the video ram as possible and seeing how many fit
2256 * you can also get the correct initial value from via X and ATI's driver
2257 *******************/
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2259 static BOOL showfixmes = TRUE;
2260 if (showfixmes) {
2261 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2262 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2263 showfixmes = FALSE;
2265 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2266 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2267 /* videomemory is simulated videomemory + AGP memory left */
2268 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2273 /*****
2274 * Get / Set FVF
2275 *****/
2276 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2278 HRESULT hr = WINED3D_OK;
2280 /* Update the current state block */
2281 This->updateStateBlock->fvf = fvf;
2282 This->updateStateBlock->changed.fvf = TRUE;
2283 This->updateStateBlock->set.fvf = TRUE;
2285 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2286 return hr;
2290 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2292 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2293 *pfvf = This->stateBlock->fvf;
2294 return WINED3D_OK;
2297 /*****
2298 * Get / Set Stream Source
2299 *****/
2300 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2302 IWineD3DVertexBuffer *oldSrc;
2304 /**TODO: instance and index data, see
2305 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2307 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2308 **************/
2310 /* D3d9 only, but shouldn't hurt d3d8 */
2311 UINT streamFlags;
2313 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2314 if (streamFlags) {
2315 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2316 FIXME("stream index data not supported\n");
2318 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2319 FIXME("stream instance data not supported\n");
2323 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2325 if (StreamNumber >= MAX_STREAMS) {
2326 WARN("Stream out of range %d\n", StreamNumber);
2327 return WINED3DERR_INVALIDCALL;
2330 oldSrc = This->stateBlock->streamSource[StreamNumber];
2331 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2333 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2334 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2335 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2336 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2337 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2338 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2340 /* Handle recording of state blocks */
2341 if (This->isRecordingState) {
2342 TRACE("Recording... not performing anything\n");
2343 return WINED3D_OK;
2346 /* Same stream object: no action */
2347 if (oldSrc == pStreamData)
2348 return WINED3D_OK;
2350 /* Need to do a getParent and pass the reffs up */
2351 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2352 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2353 so for now, just count internally */
2354 if (pStreamData != NULL) {
2355 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2356 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2357 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2359 vbImpl->stream = StreamNumber;
2360 vbImpl->Flags |= VBFLAG_STREAM;
2361 IWineD3DVertexBuffer_AddRef(pStreamData);
2363 if (oldSrc != NULL) {
2364 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2365 IWineD3DVertexBuffer_Release(oldSrc);
2368 return WINED3D_OK;
2371 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2373 UINT streamFlags;
2375 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2376 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2379 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2380 if (streamFlags) {
2381 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2382 FIXME("stream index data not supported\n");
2384 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2385 FIXME("stream instance data not supported\n");
2389 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2391 if (StreamNumber >= MAX_STREAMS) {
2392 WARN("Stream out of range %d\n", StreamNumber);
2393 return WINED3DERR_INVALIDCALL;
2395 *pStream = This->stateBlock->streamSource[StreamNumber];
2396 *pStride = This->stateBlock->streamStride[StreamNumber];
2397 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2399 if (*pStream == NULL) {
2400 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2401 return WINED3DERR_INVALIDCALL;
2404 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2405 return WINED3D_OK;
2408 /*Should be quite easy, just an extension of vertexdata
2409 ref...
2410 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2412 The divider is a bit odd though
2414 VertexOffset = StartVertex / Divider * StreamStride +
2415 VertexIndex / Divider * StreamStride + StreamOffset
2418 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2422 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2424 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2425 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2426 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2428 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2429 FIXME("Stream indexing not fully supported\n");
2432 return WINED3D_OK;
2435 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2439 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2441 TRACE("(%p) : returning %d\n", This, *Divider);
2443 return WINED3D_OK;
2446 /*****
2447 * Get / Set & Multiply Transform
2448 *****/
2449 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2452 /* Most of this routine, comments included copied from ddraw tree initially: */
2453 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2455 /* Handle recording of state blocks */
2456 if (This->isRecordingState) {
2457 TRACE("Recording... not performing anything\n");
2458 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2459 This->updateStateBlock->set.transform[d3dts] = TRUE;
2460 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2461 return WINED3D_OK;
2465 * If the new matrix is the same as the current one,
2466 * we cut off any further processing. this seems to be a reasonable
2467 * optimization because as was noticed, some apps (warcraft3 for example)
2468 * tend towards setting the same matrix repeatedly for some reason.
2470 * From here on we assume that the new matrix is different, wherever it matters.
2472 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2473 TRACE("The app is setting the same matrix over again\n");
2474 return WINED3D_OK;
2475 } else {
2476 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2480 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2481 where ViewMat = Camera space, WorldMat = world space.
2483 In OpenGL, camera and world space is combined into GL_MODELVIEW
2484 matrix. The Projection matrix stay projection matrix.
2487 /* Capture the times we can just ignore the change for now */
2488 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2489 This->modelview_valid = FALSE;
2490 return WINED3D_OK;
2492 } else if (d3dts == D3DTS_PROJECTION) {
2493 This->proj_valid = FALSE;
2494 return WINED3D_OK;
2496 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2497 /* Indexed Vertex Blending Matrices 256 -> 511 */
2498 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2499 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2500 return WINED3D_OK;
2503 /* Now we really are going to have to change a matrix */
2504 ENTER_GL();
2506 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2507 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2508 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2509 unsigned int k;
2511 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2512 * NOTE: We have to reset the positions even if the light/plane is not currently
2513 * enabled, since the call to enable it will not reset the position.
2514 * NOTE2: Apparently texture transforms do NOT need reapplying
2517 PLIGHTINFOEL *lightChain = NULL;
2518 This->modelview_valid = FALSE;
2519 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2521 glMatrixMode(GL_MODELVIEW);
2522 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2523 glPushMatrix();
2524 glLoadMatrixf((float *)lpmatrix);
2525 checkGLcall("glLoadMatrixf(...)");
2527 /* Reset lights */
2528 lightChain = This->stateBlock->lights;
2529 while (lightChain && lightChain->glIndex != -1) {
2530 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2531 checkGLcall("glLightfv posn");
2532 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2533 checkGLcall("glLightfv dirn");
2534 lightChain = lightChain->next;
2537 /* Reset Clipping Planes if clipping is enabled */
2538 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2539 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2540 checkGLcall("glClipPlane");
2542 glPopMatrix();
2544 } else { /* What was requested!?? */
2545 WARN("invalid matrix specified: %i\n", d3dts);
2548 /* Release lock, all done */
2549 LEAVE_GL();
2550 return WINED3D_OK;
2553 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2555 TRACE("(%p) : for Transform State %d\n", This, State);
2556 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2557 return WINED3D_OK;
2560 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2561 D3DMATRIX *mat = NULL;
2562 D3DMATRIX temp;
2564 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2565 * below means it will be recorded in a state block change, but it
2566 * works regardless where it is recorded.
2567 * If this is found to be wrong, change to StateBlock.
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 TRACE("(%p) : For state %u\n", This, State);
2572 if (State < HIGHEST_TRANSFORMSTATE)
2574 mat = &This->updateStateBlock->transforms[State];
2575 } else {
2576 FIXME("Unhandled transform state!!\n");
2579 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2581 /* Apply change via set transform - will reapply to eg. lights this way */
2582 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2585 /*****
2586 * Get / Set Light
2587 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2588 *****/
2589 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2590 you can reference any indexes you want as long as that number max are enabled at any
2591 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2592 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2593 but when recording, just build a chain pretty much of commands to be replayed. */
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2596 float rho;
2597 PLIGHTINFOEL *object, *temp;
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2602 /* If recording state block, just add to end of lights chain */
2603 if (This->isRecordingState) {
2604 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2605 if (NULL == object) {
2606 return WINED3DERR_OUTOFVIDEOMEMORY;
2608 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2609 object->OriginalIndex = Index;
2610 object->glIndex = -1;
2611 object->changed = TRUE;
2613 /* Add to the END of the chain of lights changes to be replayed */
2614 if (This->updateStateBlock->lights == NULL) {
2615 This->updateStateBlock->lights = object;
2616 } else {
2617 temp = This->updateStateBlock->lights;
2618 while (temp->next != NULL) temp=temp->next;
2619 temp->next = object;
2621 TRACE("Recording... not performing anything more\n");
2622 return WINED3D_OK;
2625 /* Ok, not recording any longer so do real work */
2626 object = This->stateBlock->lights;
2627 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2629 /* If we didn't find it in the list of lights, time to add it */
2630 if (object == NULL) {
2631 PLIGHTINFOEL *insertAt,*prevPos;
2633 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2634 if (NULL == object) {
2635 return WINED3DERR_OUTOFVIDEOMEMORY;
2637 object->OriginalIndex = Index;
2638 object->glIndex = -1;
2640 /* Add it to the front of list with the idea that lights will be changed as needed
2641 BUT after any lights currently assigned GL indexes */
2642 insertAt = This->stateBlock->lights;
2643 prevPos = NULL;
2644 while (insertAt != NULL && insertAt->glIndex != -1) {
2645 prevPos = insertAt;
2646 insertAt = insertAt->next;
2649 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2650 This->stateBlock->lights = object;
2651 } else if (insertAt == NULL) { /* End of list */
2652 prevPos->next = object;
2653 object->prev = prevPos;
2654 } else { /* Middle of chain */
2655 if (prevPos == NULL) {
2656 This->stateBlock->lights = object;
2657 } else {
2658 prevPos->next = object;
2660 object->prev = prevPos;
2661 object->next = insertAt;
2662 insertAt->prev = object;
2666 /* Initialize the object */
2667 TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2668 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2669 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2670 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2671 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2672 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2673 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2675 /* Save away the information */
2676 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2678 switch (pLight->Type) {
2679 case D3DLIGHT_POINT:
2680 /* Position */
2681 object->lightPosn[0] = pLight->Position.x;
2682 object->lightPosn[1] = pLight->Position.y;
2683 object->lightPosn[2] = pLight->Position.z;
2684 object->lightPosn[3] = 1.0f;
2685 object->cutoff = 180.0f;
2686 /* FIXME: Range */
2687 break;
2689 case D3DLIGHT_DIRECTIONAL:
2690 /* Direction */
2691 object->lightPosn[0] = -pLight->Direction.x;
2692 object->lightPosn[1] = -pLight->Direction.y;
2693 object->lightPosn[2] = -pLight->Direction.z;
2694 object->lightPosn[3] = 0.0;
2695 object->exponent = 0.0f;
2696 object->cutoff = 180.0f;
2697 break;
2699 case D3DLIGHT_SPOT:
2700 /* Position */
2701 object->lightPosn[0] = pLight->Position.x;
2702 object->lightPosn[1] = pLight->Position.y;
2703 object->lightPosn[2] = pLight->Position.z;
2704 object->lightPosn[3] = 1.0;
2706 /* Direction */
2707 object->lightDirn[0] = pLight->Direction.x;
2708 object->lightDirn[1] = pLight->Direction.y;
2709 object->lightDirn[2] = pLight->Direction.z;
2710 object->lightDirn[3] = 1.0;
2713 * opengl-ish and d3d-ish spot lights use too different models for the
2714 * light "intensity" as a function of the angle towards the main light direction,
2715 * so we only can approximate very roughly.
2716 * however spot lights are rather rarely used in games (if ever used at all).
2717 * furthermore if still used, probably nobody pays attention to such details.
2719 if (pLight->Falloff == 0) {
2720 rho = 6.28f;
2721 } else {
2722 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2724 if (rho < 0.0001) rho = 0.0001f;
2725 object->exponent = -0.3/log(cos(rho/2));
2726 object->cutoff = pLight->Phi*90/M_PI;
2728 /* FIXME: Range */
2729 break;
2731 default:
2732 FIXME("Unrecognized light type %d\n", pLight->Type);
2735 /* Update the live definitions if the light is currently assigned a glIndex */
2736 if (object->glIndex != -1) {
2737 setup_light(iface, object->glIndex, object);
2739 return WINED3D_OK;
2742 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2743 PLIGHTINFOEL *lightInfo = NULL;
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2745 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2747 /* Locate the light in the live lights */
2748 lightInfo = This->stateBlock->lights;
2749 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2751 if (lightInfo == NULL) {
2752 TRACE("Light information requested but light not defined\n");
2753 return WINED3DERR_INVALIDCALL;
2756 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2757 return WINED3D_OK;
2760 /*****
2761 * Get / Set Light Enable
2762 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2763 *****/
2764 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2765 PLIGHTINFOEL *lightInfo = NULL;
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2769 /* Tests show true = 128...not clear why */
2771 Enable = Enable? 128: 0;
2773 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2774 if (This->isRecordingState) {
2775 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2776 if (NULL == lightInfo) {
2777 return WINED3DERR_OUTOFVIDEOMEMORY;
2779 lightInfo->OriginalIndex = Index;
2780 lightInfo->glIndex = -1;
2781 lightInfo->enabledChanged = TRUE;
2782 lightInfo->lightEnabled = Enable;
2784 /* Add to the END of the chain of lights changes to be replayed */
2785 if (This->updateStateBlock->lights == NULL) {
2786 This->updateStateBlock->lights = lightInfo;
2787 } else {
2788 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2789 while (temp->next != NULL) temp=temp->next;
2790 temp->next = lightInfo;
2792 TRACE("Recording... not performing anything more\n");
2793 return WINED3D_OK;
2796 /* Not recording... So, locate the light in the live lights */
2797 lightInfo = This->stateBlock->lights;
2798 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2800 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2801 if (lightInfo == NULL) {
2803 TRACE("Light enabled requested but light not defined, so defining one!\n");
2804 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2806 /* Search for it again! Should be fairly quick as near head of list */
2807 lightInfo = This->stateBlock->lights;
2808 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2809 if (lightInfo == NULL) {
2810 FIXME("Adding default lights has failed dismally\n");
2811 return WINED3DERR_INVALIDCALL;
2815 /* OK, we now have a light... */
2816 if (Enable == FALSE) {
2818 /* If we are disabling it, check it was enabled, and
2819 still only do something if it has assigned a glIndex (which it should have!) */
2820 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2821 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2822 ENTER_GL();
2823 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2824 checkGLcall("glDisable GL_LIGHT0+Index");
2825 LEAVE_GL();
2826 } else {
2827 TRACE("Nothing to do as light was not enabled\n");
2829 lightInfo->lightEnabled = Enable;
2830 } else {
2832 /* We are enabling it. If it is enabled, it's really simple */
2833 if (lightInfo->lightEnabled) {
2834 /* nop */
2835 TRACE("Nothing to do as light was enabled\n");
2837 /* If it already has a glIndex, it's still simple */
2838 } else if (lightInfo->glIndex != -1) {
2839 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2840 lightInfo->lightEnabled = Enable;
2841 ENTER_GL();
2842 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2843 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2844 LEAVE_GL();
2846 /* Otherwise got to find space - lights are ordered gl indexes first */
2847 } else {
2848 PLIGHTINFOEL *bsf = NULL;
2849 PLIGHTINFOEL *pos = This->stateBlock->lights;
2850 PLIGHTINFOEL *prev = NULL;
2851 int Index= 0;
2852 int glIndex = -1;
2854 /* Try to minimize changes as much as possible */
2855 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2857 /* Try to remember which index can be replaced if necessary */
2858 if (bsf==NULL && pos->lightEnabled == FALSE) {
2859 /* Found a light we can replace, save as best replacement */
2860 bsf = pos;
2863 /* Step to next space */
2864 prev = pos;
2865 pos = pos->next;
2866 Index ++;
2869 /* If we have too many active lights, fail the call */
2870 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2871 FIXME("Program requests too many concurrent lights\n");
2872 return WINED3DERR_INVALIDCALL;
2874 /* If we have allocated all lights, but not all are enabled,
2875 reuse one which is not enabled */
2876 } else if (Index == This->maxConcurrentLights) {
2877 /* use bsf - Simply swap the new light and the BSF one */
2878 PLIGHTINFOEL *bsfNext = bsf->next;
2879 PLIGHTINFOEL *bsfPrev = bsf->prev;
2881 /* Sort out ends */
2882 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2883 if (bsf->prev != NULL) {
2884 bsf->prev->next = lightInfo;
2885 } else {
2886 This->stateBlock->lights = lightInfo;
2889 /* If not side by side, lots of chains to update */
2890 if (bsf->next != lightInfo) {
2891 lightInfo->prev->next = bsf;
2892 bsf->next->prev = lightInfo;
2893 bsf->next = lightInfo->next;
2894 bsf->prev = lightInfo->prev;
2895 lightInfo->next = bsfNext;
2896 lightInfo->prev = bsfPrev;
2898 } else {
2899 /* Simple swaps */
2900 bsf->prev = lightInfo;
2901 bsf->next = lightInfo->next;
2902 lightInfo->next = bsf;
2903 lightInfo->prev = bsfPrev;
2907 /* Update states */
2908 glIndex = bsf->glIndex;
2909 bsf->glIndex = -1;
2910 lightInfo->glIndex = glIndex;
2911 lightInfo->lightEnabled = Enable;
2913 /* Finally set up the light in gl itself */
2914 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2915 ENTER_GL();
2916 setup_light(iface, glIndex, lightInfo);
2917 glEnable(GL_LIGHT0 + glIndex);
2918 checkGLcall("glEnable GL_LIGHT0 new setup");
2919 LEAVE_GL();
2921 /* If we reached the end of the allocated lights, with space in the
2922 gl lights, setup a new light */
2923 } else if (pos->glIndex == -1) {
2925 /* We reached the end of the allocated gl lights, so already
2926 know the index of the next one! */
2927 glIndex = Index;
2928 lightInfo->glIndex = glIndex;
2929 lightInfo->lightEnabled = Enable;
2931 /* In an ideal world, it's already in the right place */
2932 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2933 /* No need to move it */
2934 } else {
2935 /* Remove this light from the list */
2936 lightInfo->prev->next = lightInfo->next;
2937 if (lightInfo->next != NULL) {
2938 lightInfo->next->prev = lightInfo->prev;
2941 /* Add in at appropriate place (inbetween prev and pos) */
2942 lightInfo->prev = prev;
2943 lightInfo->next = pos;
2944 if (prev == NULL) {
2945 This->stateBlock->lights = lightInfo;
2946 } else {
2947 prev->next = lightInfo;
2949 if (pos != NULL) {
2950 pos->prev = lightInfo;
2954 /* Finally set up the light in gl itself */
2955 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2956 ENTER_GL();
2957 setup_light(iface, glIndex, lightInfo);
2958 glEnable(GL_LIGHT0 + glIndex);
2959 checkGLcall("glEnable GL_LIGHT0 new setup");
2960 LEAVE_GL();
2965 return WINED3D_OK;
2968 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2970 PLIGHTINFOEL *lightInfo = NULL;
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 TRACE("(%p) : for idx(%ld)\n", This, Index);
2974 /* Locate the light in the live lights */
2975 lightInfo = This->stateBlock->lights;
2976 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2978 if (lightInfo == NULL) {
2979 TRACE("Light enabled state requested but light not defined\n");
2980 return WINED3DERR_INVALIDCALL;
2982 *pEnable = lightInfo->lightEnabled;
2983 return WINED3D_OK;
2986 /*****
2987 * Get / Set Clip Planes
2988 *****/
2989 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2991 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2993 /* Validate Index */
2994 if (Index >= GL_LIMITS(clipplanes)) {
2995 TRACE("Application has requested clipplane this device doesn't support\n");
2996 return WINED3DERR_INVALIDCALL;
2999 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3000 This->updateStateBlock->set.clipplane[Index] = TRUE;
3001 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3002 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3003 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3004 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3006 /* Handle recording of state blocks */
3007 if (This->isRecordingState) {
3008 TRACE("Recording... not performing anything\n");
3009 return WINED3D_OK;
3012 /* Apply it */
3014 ENTER_GL();
3016 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3017 glMatrixMode(GL_MODELVIEW);
3018 glPushMatrix();
3019 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3021 TRACE("Clipplane [%f,%f,%f,%f]\n",
3022 This->updateStateBlock->clipplane[Index][0],
3023 This->updateStateBlock->clipplane[Index][1],
3024 This->updateStateBlock->clipplane[Index][2],
3025 This->updateStateBlock->clipplane[Index][3]);
3026 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3027 checkGLcall("glClipPlane");
3029 glPopMatrix();
3030 LEAVE_GL();
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 TRACE("(%p) : for idx %ld\n", This, Index);
3039 /* Validate Index */
3040 if (Index >= GL_LIMITS(clipplanes)) {
3041 TRACE("Application has requested clipplane this device doesn't support\n");
3042 return WINED3DERR_INVALIDCALL;
3045 pPlane[0] = This->stateBlock->clipplane[Index][0];
3046 pPlane[1] = This->stateBlock->clipplane[Index][1];
3047 pPlane[2] = This->stateBlock->clipplane[Index][2];
3048 pPlane[3] = This->stateBlock->clipplane[Index][3];
3049 return WINED3D_OK;
3052 /*****
3053 * Get / Set Clip Plane Status
3054 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3055 *****/
3056 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 FIXME("(%p) : stub\n", This);
3059 if (NULL == pClipStatus) {
3060 return WINED3DERR_INVALIDCALL;
3062 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3063 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3064 return WINED3D_OK;
3067 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 FIXME("(%p) : stub\n", This);
3070 if (NULL == pClipStatus) {
3071 return WINED3DERR_INVALIDCALL;
3073 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3074 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3075 return WINED3D_OK;
3078 /*****
3079 * Get / Set Material
3080 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3081 *****/
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 This->updateStateBlock->changed.material = TRUE;
3086 This->updateStateBlock->set.material = TRUE;
3087 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3089 /* Handle recording of state blocks */
3090 if (This->isRecordingState) {
3091 TRACE("Recording... not performing anything\n");
3092 return WINED3D_OK;
3095 ENTER_GL();
3096 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3097 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3098 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3099 pMaterial->Ambient.b, pMaterial->Ambient.a);
3100 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3101 pMaterial->Specular.b, pMaterial->Specular.a);
3102 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3103 pMaterial->Emissive.b, pMaterial->Emissive.a);
3104 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3106 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3107 checkGLcall("glMaterialfv(GL_AMBIENT)");
3108 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3109 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3111 /* Only change material color if specular is enabled, otherwise it is set to black */
3112 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3113 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3114 checkGLcall("glMaterialfv(GL_SPECULAR");
3115 } else {
3116 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3117 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3118 checkGLcall("glMaterialfv(GL_SPECULAR");
3120 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3121 checkGLcall("glMaterialfv(GL_EMISSION)");
3122 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3123 checkGLcall("glMaterialf(GL_SHININESS");
3125 LEAVE_GL();
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3132 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3133 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3134 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3135 pMaterial->Ambient.b, pMaterial->Ambient.a);
3136 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3137 pMaterial->Specular.b, pMaterial->Specular.a);
3138 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3139 pMaterial->Emissive.b, pMaterial->Emissive.a);
3140 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3142 return WINED3D_OK;
3145 /*****
3146 * Get / Set Indices
3147 *****/
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3149 UINT BaseVertexIndex) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 IWineD3DIndexBuffer *oldIdxs;
3153 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3154 oldIdxs = This->updateStateBlock->pIndexData;
3156 This->updateStateBlock->changed.indices = TRUE;
3157 This->updateStateBlock->set.indices = TRUE;
3158 This->updateStateBlock->pIndexData = pIndexData;
3159 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3161 /* Handle recording of state blocks */
3162 if (This->isRecordingState) {
3163 TRACE("Recording... not performing anything\n");
3164 return WINED3D_OK;
3167 if (NULL != pIndexData) {
3168 IWineD3DIndexBuffer_AddRef(pIndexData);
3170 if (NULL != oldIdxs) {
3171 IWineD3DIndexBuffer_Release(oldIdxs);
3173 return WINED3D_OK;
3176 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3179 *ppIndexData = This->stateBlock->pIndexData;
3181 /* up ref count on ppindexdata */
3182 if (*ppIndexData) {
3183 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3184 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3185 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3186 }else{
3187 TRACE("(%p) No index data set\n", This);
3189 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3191 return WINED3D_OK;
3194 /*****
3195 * Get / Set Viewports
3196 *****/
3197 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3200 TRACE("(%p)\n", This);
3201 This->updateStateBlock->changed.viewport = TRUE;
3202 This->updateStateBlock->set.viewport = TRUE;
3203 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3205 /* Handle recording of state blocks */
3206 if (This->isRecordingState) {
3207 TRACE("Recording... not performing anything\n");
3208 return WINED3D_OK;
3210 This->viewport_changed = TRUE;
3212 ENTER_GL();
3214 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3215 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3217 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3218 checkGLcall("glDepthRange");
3219 /* Note: GL requires lower left, DirectX supplies upper left */
3220 /* TODO: replace usage of renderTarget with context management */
3221 glViewport(pViewport->X,
3222 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3223 pViewport->Width, pViewport->Height);
3225 checkGLcall("glViewport");
3227 LEAVE_GL();
3229 return WINED3D_OK;
3233 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3235 TRACE("(%p)\n", This);
3236 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3237 return WINED3D_OK;
3240 static void renderstate_stencil_twosided(
3241 IWineD3DDeviceImpl *This,
3242 GLint face,
3243 GLint func,
3244 GLint ref,
3245 GLuint mask,
3246 GLint stencilFail,
3247 GLint depthFail,
3248 GLint stencilPass ) {
3249 #if 0 /* Don't use OpenGL 2.0 calls for now */
3250 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3251 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3252 checkGLcall("glStencilFuncSeparate(...)");
3253 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3254 checkGLcall("glStencilOpSeparate(...)");
3256 else
3257 #endif
3258 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3259 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3260 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3261 GL_EXTCALL(glActiveStencilFaceEXT(face));
3262 checkGLcall("glActiveStencilFaceEXT(...)");
3263 glStencilFunc(func, ref, mask);
3264 checkGLcall("glStencilFunc(...)");
3265 glStencilOp(stencilFail, depthFail, stencilPass);
3266 checkGLcall("glStencilOp(...)");
3267 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3268 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3269 checkGLcall("glStencilFuncSeparateATI(...)");
3270 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3271 checkGLcall("glStencilOpSeparateATI(...)");
3272 } else {
3273 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3277 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3278 DWORD onesided_enable = FALSE;
3279 DWORD twosided_enable = FALSE;
3280 GLint func = GL_ALWAYS;
3281 GLint func_ccw = GL_ALWAYS;
3282 GLint ref = 0;
3283 GLuint mask = 0;
3284 GLint stencilFail = GL_KEEP;
3285 GLint depthFail = GL_KEEP;
3286 GLint stencilPass = GL_KEEP;
3287 GLint stencilFail_ccw = GL_KEEP;
3288 GLint depthFail_ccw = GL_KEEP;
3289 GLint stencilPass_ccw = GL_KEEP;
3291 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3292 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3293 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3294 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3295 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3296 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3297 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3298 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3299 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3300 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3301 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3302 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3303 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3304 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3305 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3306 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3307 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3308 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3309 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3310 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3311 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3312 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3313 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3314 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3316 switch(State) {
3317 case WINED3DRS_STENCILENABLE :
3318 onesided_enable = Value;
3319 break;
3320 case WINED3DRS_TWOSIDEDSTENCILMODE :
3321 twosided_enable = Value;
3322 break;
3323 case WINED3DRS_STENCILFUNC :
3324 func = StencilFunc(Value);
3325 break;
3326 case WINED3DRS_CCW_STENCILFUNC :
3327 func_ccw = StencilFunc(Value);
3328 break;
3329 case WINED3DRS_STENCILREF :
3330 ref = Value;
3331 break;
3332 case WINED3DRS_STENCILMASK :
3333 mask = Value;
3334 break;
3335 case WINED3DRS_STENCILFAIL :
3336 stencilFail = StencilOp(Value);
3337 break;
3338 case WINED3DRS_STENCILZFAIL :
3339 depthFail = StencilOp(Value);
3340 break;
3341 case WINED3DRS_STENCILPASS :
3342 stencilPass = StencilOp(Value);
3343 break;
3344 case WINED3DRS_CCW_STENCILFAIL :
3345 stencilFail_ccw = StencilOp(Value);
3346 break;
3347 case WINED3DRS_CCW_STENCILZFAIL :
3348 depthFail_ccw = StencilOp(Value);
3349 break;
3350 case WINED3DRS_CCW_STENCILPASS :
3351 stencilPass_ccw = StencilOp(Value);
3352 break;
3353 default :
3354 ERR("This should not happen!");
3357 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3358 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3359 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3360 onesided_enable, twosided_enable, ref, mask,
3361 func, stencilFail, depthFail, stencilPass,
3362 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3364 if (twosided_enable) {
3365 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3366 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3367 } else {
3368 if (onesided_enable) {
3369 glEnable(GL_STENCIL_TEST);
3370 checkGLcall("glEnable GL_STENCIL_TEST");
3371 glStencilFunc(func, ref, mask);
3372 checkGLcall("glStencilFunc(...)");
3373 glStencilOp(stencilFail, depthFail, stencilPass);
3374 checkGLcall("glStencilOp(...)");
3375 } else {
3376 glDisable(GL_STENCIL_TEST);
3377 checkGLcall("glDisable GL_STENCIL_TEST");
3382 /*****
3383 * Get / Set Render States
3384 * TODO: Verify against dx9 definitions
3385 *****/
3386 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3389 DWORD OldValue = This->stateBlock->renderState[State];
3391 /* Simple way of referring to either a DWORD or a 4 byte float */
3392 union {
3393 DWORD d;
3394 float f;
3395 } tmpvalue;
3397 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3398 This->updateStateBlock->changed.renderState[State] = TRUE;
3399 This->updateStateBlock->set.renderState[State] = TRUE;
3400 This->updateStateBlock->renderState[State] = Value;
3402 /* Handle recording of state blocks */
3403 if (This->isRecordingState) {
3404 TRACE("Recording... not performing anything\n");
3405 return WINED3D_OK;
3408 ENTER_GL();
3410 switch (State) {
3411 case WINED3DRS_FILLMODE :
3412 switch ((D3DFILLMODE) Value) {
3413 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3414 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3415 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3416 default:
3417 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3419 checkGLcall("glPolygonMode (fillmode)");
3420 break;
3422 case WINED3DRS_LIGHTING :
3423 if (Value) {
3424 glEnable(GL_LIGHTING);
3425 checkGLcall("glEnable GL_LIGHTING");
3426 } else {
3427 glDisable(GL_LIGHTING);
3428 checkGLcall("glDisable GL_LIGHTING");
3430 break;
3432 case WINED3DRS_ZENABLE :
3433 switch ((D3DZBUFFERTYPE) Value) {
3434 case D3DZB_FALSE:
3435 glDisable(GL_DEPTH_TEST);
3436 checkGLcall("glDisable GL_DEPTH_TEST");
3437 break;
3438 case D3DZB_TRUE:
3439 glEnable(GL_DEPTH_TEST);
3440 checkGLcall("glEnable GL_DEPTH_TEST");
3441 break;
3442 case D3DZB_USEW:
3443 glEnable(GL_DEPTH_TEST);
3444 checkGLcall("glEnable GL_DEPTH_TEST");
3445 FIXME("W buffer is not well handled\n");
3446 break;
3447 default:
3448 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3450 break;
3452 case WINED3DRS_CULLMODE :
3454 /* If we are culling "back faces with clockwise vertices" then
3455 set front faces to be counter clockwise and enable culling
3456 of back faces */
3457 switch ((D3DCULL) Value) {
3458 case D3DCULL_NONE:
3459 glDisable(GL_CULL_FACE);
3460 checkGLcall("glDisable GL_CULL_FACE");
3461 break;
3462 case D3DCULL_CW:
3463 glEnable(GL_CULL_FACE);
3464 checkGLcall("glEnable GL_CULL_FACE");
3465 if (This->renderUpsideDown) {
3466 glFrontFace(GL_CW);
3467 checkGLcall("glFrontFace GL_CW");
3468 } else {
3469 glFrontFace(GL_CCW);
3470 checkGLcall("glFrontFace GL_CCW");
3472 glCullFace(GL_BACK);
3473 break;
3474 case D3DCULL_CCW:
3475 glEnable(GL_CULL_FACE);
3476 checkGLcall("glEnable GL_CULL_FACE");
3477 if (This->renderUpsideDown) {
3478 glFrontFace(GL_CCW);
3479 checkGLcall("glFrontFace GL_CCW");
3480 } else {
3481 glFrontFace(GL_CW);
3482 checkGLcall("glFrontFace GL_CW");
3484 glCullFace(GL_BACK);
3485 break;
3486 default:
3487 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3489 break;
3491 case WINED3DRS_SHADEMODE :
3492 switch ((D3DSHADEMODE) Value) {
3493 case D3DSHADE_FLAT:
3494 glShadeModel(GL_FLAT);
3495 checkGLcall("glShadeModel");
3496 break;
3497 case D3DSHADE_GOURAUD:
3498 glShadeModel(GL_SMOOTH);
3499 checkGLcall("glShadeModel");
3500 break;
3501 case D3DSHADE_PHONG:
3502 FIXME("D3DSHADE_PHONG isn't supported\n");
3503 break;
3504 default:
3505 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3507 break;
3509 case WINED3DRS_DITHERENABLE :
3510 if (Value) {
3511 glEnable(GL_DITHER);
3512 checkGLcall("glEnable GL_DITHER");
3513 } else {
3514 glDisable(GL_DITHER);
3515 checkGLcall("glDisable GL_DITHER");
3517 break;
3519 case WINED3DRS_ZWRITEENABLE :
3520 if (Value) {
3521 glDepthMask(1);
3522 checkGLcall("glDepthMask");
3523 } else {
3524 glDepthMask(0);
3525 checkGLcall("glDepthMask");
3527 break;
3529 case WINED3DRS_ZFUNC :
3531 int glParm = GL_LESS;
3533 switch ((D3DCMPFUNC) Value) {
3534 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3535 case D3DCMP_LESS: glParm=GL_LESS; break;
3536 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3537 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3538 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3539 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3540 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3541 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3542 default:
3543 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3545 glDepthFunc(glParm);
3546 checkGLcall("glDepthFunc");
3548 break;
3550 case WINED3DRS_AMBIENT :
3552 float col[4];
3553 D3DCOLORTOGLFLOAT4(Value, col);
3554 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3555 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3556 checkGLcall("glLightModel for MODEL_AMBIENT");
3559 break;
3561 case WINED3DRS_ALPHABLENDENABLE :
3562 if (Value) {
3563 glEnable(GL_BLEND);
3564 checkGLcall("glEnable GL_BLEND");
3565 } else {
3566 glDisable(GL_BLEND);
3567 checkGLcall("glDisable GL_BLEND");
3569 break;
3571 case WINED3DRS_SRCBLEND :
3572 case WINED3DRS_DESTBLEND :
3574 int newVal = GL_ZERO;
3575 switch (Value) {
3576 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3577 case D3DBLEND_ONE : newVal = GL_ONE; break;
3578 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3579 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3580 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3581 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3582 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3583 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3584 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3585 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3586 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3588 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3589 This->srcBlend = newVal;
3590 This->dstBlend = newVal;
3591 break;
3593 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3594 This->srcBlend = newVal;
3595 This->dstBlend = newVal;
3596 break;
3597 default:
3598 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3601 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3602 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3603 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3604 glBlendFunc(This->srcBlend, This->dstBlend);
3606 checkGLcall("glBlendFunc");
3608 break;
3610 case WINED3DRS_ALPHATESTENABLE :
3611 case WINED3DRS_ALPHAFUNC :
3612 case WINED3DRS_ALPHAREF :
3613 case WINED3DRS_COLORKEYENABLE :
3615 int glParm = 0.0;
3616 float ref = GL_LESS;
3617 BOOL enable_ckey = FALSE;
3619 IWineD3DSurfaceImpl *surf;
3621 /* Find out if the texture on the first stage has a ckey set */
3622 if(This->stateBlock->textures[0]) {
3623 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3624 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3627 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3628 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3629 glEnable(GL_ALPHA_TEST);
3630 checkGLcall("glEnable GL_ALPHA_TEST");
3631 } else {
3632 glDisable(GL_ALPHA_TEST);
3633 checkGLcall("glDisable GL_ALPHA_TEST");
3634 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3635 * enable call
3637 break;
3640 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3641 glParm = GL_NOTEQUAL;
3642 ref = 0.0;
3643 } else {
3644 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3646 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3647 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3648 case D3DCMP_LESS: glParm = GL_LESS; break;
3649 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3650 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3651 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3652 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3653 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3654 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3655 default:
3656 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3659 This->alphafunc = glParm;
3660 glAlphaFunc(glParm, ref);
3661 checkGLcall("glAlphaFunc");
3663 break;
3665 case WINED3DRS_CLIPPLANEENABLE :
3666 case WINED3DRS_CLIPPING :
3668 /* Ensure we only do the changed clip planes */
3669 DWORD enable = 0xFFFFFFFF;
3670 DWORD disable = 0x00000000;
3672 /* If enabling / disabling all */
3673 if (State == WINED3DRS_CLIPPING) {
3674 if (Value) {
3675 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3676 disable = 0x00;
3677 } else {
3678 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3679 enable = 0x00;
3681 } else {
3682 enable = Value & ~OldValue;
3683 disable = ~Value & OldValue;
3686 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3687 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3688 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3689 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3690 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3691 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3693 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3694 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3695 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3696 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3697 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3698 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3700 /** update clipping status */
3701 if (enable) {
3702 This->stateBlock->clip_status.ClipUnion = 0;
3703 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3704 } else {
3705 This->stateBlock->clip_status.ClipUnion = 0;
3706 This->stateBlock->clip_status.ClipIntersection = 0;
3709 break;
3711 case WINED3DRS_BLENDOP :
3713 int glParm = GL_FUNC_ADD;
3715 switch ((D3DBLENDOP) Value) {
3716 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3717 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3718 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3719 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3720 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3721 default:
3722 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3725 if(GL_SUPPORT(ARB_IMAGING)) {
3726 TRACE("glBlendEquation(%x)\n", glParm);
3727 GL_EXTCALL(glBlendEquation(glParm));
3728 checkGLcall("glBlendEquation");
3729 } else {
3730 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3733 break;
3735 case WINED3DRS_TEXTUREFACTOR :
3737 unsigned int i;
3739 /* Note the texture color applies to all textures whereas
3740 GL_TEXTURE_ENV_COLOR applies to active only */
3741 float col[4];
3742 D3DCOLORTOGLFLOAT4(Value, col);
3743 /* Set the default alpha blend color */
3744 if (GL_SUPPORT(ARB_IMAGING)) {
3745 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3746 checkGLcall("glBlendColor");
3747 } else {
3748 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3751 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3752 /* And now the default texture color as well */
3753 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3754 /* Note the D3DRS value applies to all textures, but GL has one
3755 per texture, so apply it now ready to be used! */
3756 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3757 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3758 checkGLcall("glActiveTextureARB");
3759 } else if (i>0) {
3760 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3763 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3764 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3768 break;
3770 case WINED3DRS_SPECULARENABLE :
3772 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3773 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3774 specular color. This is wrong:
3775 Separate specular color means the specular colour is maintained separately, whereas
3776 single color means it is merged in. However in both cases they are being used to
3777 some extent.
3778 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3779 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3780 running 1.4 yet!
3783 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3784 * Instead, we need to setup the FinalCombiner properly.
3786 * The default setup for the FinalCombiner is:
3788 * <variable> <input> <mapping> <usage>
3789 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3790 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3791 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3792 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3793 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3794 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3795 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3797 * That's pretty much fine as it is, except for variable B, which needs to take
3798 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3799 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3802 if (Value) {
3803 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3804 checkGLcall("glMaterialfv");
3805 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3806 glEnable(GL_COLOR_SUM_EXT);
3807 } else {
3808 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3810 checkGLcall("glEnable(GL_COLOR_SUM)");
3812 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3813 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3814 checkGLcall("glFinalCombinerInputNV()");
3816 } else {
3817 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3819 /* for the case of enabled lighting: */
3820 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3821 checkGLcall("glMaterialfv");
3823 /* for the case of disabled lighting: */
3824 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3825 glDisable(GL_COLOR_SUM_EXT);
3826 } else {
3827 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3829 checkGLcall("glDisable(GL_COLOR_SUM)");
3831 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3832 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3833 checkGLcall("glFinalCombinerInputNV()");
3837 break;
3839 case WINED3DRS_STENCILENABLE :
3840 case WINED3DRS_TWOSIDEDSTENCILMODE :
3841 case WINED3DRS_STENCILFUNC :
3842 case WINED3DRS_CCW_STENCILFUNC :
3843 case WINED3DRS_STENCILREF :
3844 case WINED3DRS_STENCILMASK :
3845 case WINED3DRS_STENCILFAIL :
3846 case WINED3DRS_STENCILZFAIL :
3847 case WINED3DRS_STENCILPASS :
3848 case WINED3DRS_CCW_STENCILFAIL :
3849 case WINED3DRS_CCW_STENCILZFAIL :
3850 case WINED3DRS_CCW_STENCILPASS :
3851 renderstate_stencil(This, State, Value);
3852 break;
3853 case WINED3DRS_STENCILWRITEMASK :
3855 glStencilMask(Value);
3856 TRACE("glStencilMask(%lu)\n", Value);
3857 checkGLcall("glStencilMask");
3859 break;
3861 case WINED3DRS_FOGENABLE :
3863 if (Value) {
3864 glEnable(GL_FOG);
3865 checkGLcall("glEnable GL_FOG");
3866 } else {
3867 glDisable(GL_FOG);
3868 checkGLcall("glDisable GL_FOG");
3871 break;
3873 case WINED3DRS_RANGEFOGENABLE :
3875 if (Value) {
3876 TRACE("Enabled RANGEFOG");
3877 } else {
3878 TRACE("Disabled RANGEFOG");
3881 break;
3883 case WINED3DRS_FOGCOLOR :
3885 float col[4];
3886 D3DCOLORTOGLFLOAT4(Value, col);
3887 /* Set the default alpha blend color */
3888 glFogfv(GL_FOG_COLOR, &col[0]);
3889 checkGLcall("glFog GL_FOG_COLOR");
3891 break;
3893 case WINED3DRS_FOGTABLEMODE :
3894 case WINED3DRS_FOGVERTEXMODE :
3896 /* 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." */
3897 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3898 glHint(GL_FOG_HINT, GL_FASTEST);
3899 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3900 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3901 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3902 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3904 case D3DFOG_EXP: {
3905 if(!This->last_was_rhw) {
3906 glFogi(GL_FOG_MODE, GL_EXP);
3907 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3908 if(GL_SUPPORT(EXT_FOG_COORD)) {
3909 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3910 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3911 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3912 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3914 break;
3917 case D3DFOG_EXP2: {
3918 if(!This->last_was_rhw) {
3919 glFogi(GL_FOG_MODE, GL_EXP2);
3920 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3921 if(GL_SUPPORT(EXT_FOG_COORD)) {
3922 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3923 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3924 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3925 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3927 break;
3930 case D3DFOG_LINEAR: {
3931 if(!This->last_was_rhw) {
3932 glFogi(GL_FOG_MODE, GL_LINEAR);
3933 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3934 if(GL_SUPPORT(EXT_FOG_COORD)) {
3935 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3936 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3937 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3938 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3940 break;
3943 case D3DFOG_NONE: {
3944 /* Both are none? According to msdn the alpha channel of the specular
3945 * color contains a fog factor. Set it in drawStridedSlow.
3946 * Same happens with Vertexfog on transformed vertices
3948 if(GL_SUPPORT(EXT_FOG_COORD)) {
3949 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3950 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3951 glFogi(GL_FOG_MODE, GL_LINEAR);
3952 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3953 glFogf(GL_FOG_START, (float) 0xff);
3954 checkGLcall("glFogfv GL_FOG_START");
3955 glFogf(GL_FOG_END, 0.0);
3956 checkGLcall("glFogfv GL_FOG_END");
3957 } else {
3958 /* Disable GL fog, handle this in software in drawStridedSlow */
3959 glDisable(GL_FOG);
3960 checkGLcall("glDisable(GL_FOG)");
3962 break;
3964 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3966 } else {
3967 glHint(GL_FOG_HINT, GL_NICEST);
3968 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3969 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3970 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3971 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3972 if(GL_SUPPORT(EXT_FOG_COORD)) {
3973 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3974 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3975 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3976 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3978 break;
3979 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3980 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3981 if(GL_SUPPORT(EXT_FOG_COORD)) {
3982 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3983 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3984 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3985 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3987 break;
3988 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3989 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3990 if(GL_SUPPORT(EXT_FOG_COORD)) {
3991 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3992 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3993 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3994 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3996 break;
3997 case D3DFOG_NONE: /* Won't happen */
3998 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4001 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4002 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4005 break;
4007 case WINED3DRS_FOGSTART :
4009 tmpvalue.d = Value;
4010 glFogfv(GL_FOG_START, &tmpvalue.f);
4011 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4012 TRACE("Fog Start == %f\n", tmpvalue.f);
4014 break;
4016 case WINED3DRS_FOGEND :
4018 tmpvalue.d = Value;
4019 glFogfv(GL_FOG_END, &tmpvalue.f);
4020 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4021 TRACE("Fog End == %f\n", tmpvalue.f);
4023 break;
4025 case WINED3DRS_FOGDENSITY :
4027 tmpvalue.d = Value;
4028 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4029 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4031 break;
4033 case WINED3DRS_VERTEXBLEND :
4035 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4036 TRACE("Vertex Blending state to %ld\n", Value);
4038 break;
4040 case WINED3DRS_TWEENFACTOR :
4042 tmpvalue.d = Value;
4043 This->updateStateBlock->tween_factor = tmpvalue.f;
4044 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4046 break;
4048 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4050 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4052 break;
4054 case WINED3DRS_COLORVERTEX :
4055 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4056 case WINED3DRS_SPECULARMATERIALSOURCE :
4057 case WINED3DRS_AMBIENTMATERIALSOURCE :
4058 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4060 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4062 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4063 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4064 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4065 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4066 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4067 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4069 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4070 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4071 Parm = GL_AMBIENT_AND_DIFFUSE;
4072 } else {
4073 Parm = GL_DIFFUSE;
4075 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4076 Parm = GL_AMBIENT;
4077 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4078 Parm = GL_EMISSION;
4079 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4080 Parm = GL_SPECULAR;
4081 } else {
4082 Parm = -1;
4085 if (Parm == -1) {
4086 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4087 } else {
4088 This->tracking_color = NEEDS_TRACKING;
4089 This->tracking_parm = Parm;
4092 } else {
4093 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4096 break;
4098 case WINED3DRS_LINEPATTERN :
4100 union {
4101 DWORD d;
4102 D3DLINEPATTERN lp;
4103 } tmppattern;
4104 tmppattern.d = Value;
4106 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4108 if (tmppattern.lp.wRepeatFactor) {
4109 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4110 checkGLcall("glLineStipple(repeat, linepattern)");
4111 glEnable(GL_LINE_STIPPLE);
4112 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4113 } else {
4114 glDisable(GL_LINE_STIPPLE);
4115 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4118 break;
4120 case WINED3DRS_ZBIAS : /* D3D8 only */
4122 if (Value) {
4123 tmpvalue.d = Value;
4124 TRACE("ZBias value %f\n", tmpvalue.f);
4125 glPolygonOffset(0, -tmpvalue.f);
4126 checkGLcall("glPolygonOffset(0, -Value)");
4127 glEnable(GL_POLYGON_OFFSET_FILL);
4128 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4129 glEnable(GL_POLYGON_OFFSET_LINE);
4130 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4131 glEnable(GL_POLYGON_OFFSET_POINT);
4132 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4133 } else {
4134 glDisable(GL_POLYGON_OFFSET_FILL);
4135 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4136 glDisable(GL_POLYGON_OFFSET_LINE);
4137 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4138 glDisable(GL_POLYGON_OFFSET_POINT);
4139 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4142 break;
4144 case WINED3DRS_NORMALIZENORMALS :
4145 if (Value) {
4146 glEnable(GL_NORMALIZE);
4147 checkGLcall("glEnable(GL_NORMALIZE);");
4148 } else {
4149 glDisable(GL_NORMALIZE);
4150 checkGLcall("glDisable(GL_NORMALIZE);");
4152 break;
4154 case WINED3DRS_POINTSIZE :
4155 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4156 tmpvalue.d = Value;
4157 TRACE("Set point size to %f\n", tmpvalue.f);
4158 glPointSize(tmpvalue.f);
4159 checkGLcall("glPointSize(...);");
4160 break;
4162 case WINED3DRS_POINTSIZE_MIN :
4163 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4164 tmpvalue.d = Value;
4165 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4166 checkGLcall("glPointParameterfEXT(...);");
4167 } else {
4168 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4170 break;
4172 case WINED3DRS_POINTSIZE_MAX :
4173 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4174 tmpvalue.d = Value;
4175 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4176 checkGLcall("glPointParameterfEXT(...);");
4177 } else {
4178 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4180 break;
4182 case WINED3DRS_POINTSCALE_A :
4183 case WINED3DRS_POINTSCALE_B :
4184 case WINED3DRS_POINTSCALE_C :
4185 case WINED3DRS_POINTSCALEENABLE :
4188 * POINTSCALEENABLE controls how point size value is treated. If set to
4189 * true, the point size is scaled with respect to height of viewport.
4190 * When set to false point size is in pixels.
4192 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4195 /* Default values */
4196 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4199 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4200 * This means that OpenGL will clamp really small point sizes to 1.0f.
4201 * To correct for this we need to multiply by the scale factor when sizes
4202 * are less than 1.0f. scale_factor = 1.0f / point_size.
4204 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4205 if(pointSize > 0.0f) {
4206 GLfloat scaleFactor;
4208 if(pointSize < 1.0f) {
4209 scaleFactor = pointSize * pointSize;
4210 } else {
4211 scaleFactor = 1.0f;
4214 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4215 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4216 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4217 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4218 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4219 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4220 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4224 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4225 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4226 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4228 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4229 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4230 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4231 } else {
4232 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4234 break;
4236 case WINED3DRS_COLORWRITEENABLE :
4238 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4239 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4240 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4241 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4242 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4243 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4244 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4245 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4246 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4247 checkGLcall("glColorMask(...)");
4249 break;
4251 case WINED3DRS_LOCALVIEWER :
4253 GLint state = (Value) ? 1 : 0;
4254 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4255 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4257 break;
4259 case WINED3DRS_LASTPIXEL :
4261 if (Value) {
4262 TRACE("Last Pixel Drawing Enabled\n");
4263 } else {
4264 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4267 break;
4269 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4271 if (Value) {
4272 TRACE("Software Processing Enabled\n");
4273 } else {
4274 TRACE("Software Processing Disabled\n");
4277 break;
4279 /** not supported */
4280 case WINED3DRS_ZVISIBLE :
4282 LEAVE_GL();
4283 return WINED3DERR_INVALIDCALL;
4285 case WINED3DRS_POINTSPRITEENABLE :
4287 /* TODO: NV_POINT_SPRITE */
4288 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4289 TRACE("Point sprites not supported\n");
4290 break;
4294 * Point sprites are always enabled. Value controls texture coordinate
4295 * replacement mode. Must be set true for point sprites to use
4296 * textures.
4298 glEnable(GL_POINT_SPRITE_ARB);
4299 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4301 if (Value) {
4302 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4303 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4304 } else {
4305 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4306 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4308 break;
4310 case WINED3DRS_EDGEANTIALIAS :
4312 if(Value) {
4313 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4314 glEnable(GL_BLEND);
4315 checkGLcall("glEnable(GL_BLEND)");
4316 glEnable(GL_LINE_SMOOTH);
4317 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4318 } else {
4319 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4320 glDisable(GL_BLEND);
4321 checkGLcall("glDisable(GL_BLEND)");
4323 glDisable(GL_LINE_SMOOTH);
4324 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4326 break;
4328 case WINED3DRS_WRAP0 :
4329 case WINED3DRS_WRAP1 :
4330 case WINED3DRS_WRAP2 :
4331 case WINED3DRS_WRAP3 :
4332 case WINED3DRS_WRAP4 :
4333 case WINED3DRS_WRAP5 :
4334 case WINED3DRS_WRAP6 :
4335 case WINED3DRS_WRAP7 :
4336 case WINED3DRS_WRAP8 :
4337 case WINED3DRS_WRAP9 :
4338 case WINED3DRS_WRAP10 :
4339 case WINED3DRS_WRAP11 :
4340 case WINED3DRS_WRAP12 :
4341 case WINED3DRS_WRAP13 :
4342 case WINED3DRS_WRAP14 :
4343 case WINED3DRS_WRAP15 :
4345 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4346 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4347 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4348 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4349 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4351 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4353 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4354 break;
4355 case WINED3DRS_MULTISAMPLEANTIALIAS :
4357 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4358 TRACE("Multisample antialiasing not supported\n");
4359 break;
4362 if(Value) {
4363 glEnable(GL_MULTISAMPLE_ARB);
4364 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4365 } else {
4366 glDisable(GL_MULTISAMPLE_ARB);
4367 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4369 break;
4371 case WINED3DRS_SCISSORTESTENABLE :
4373 if(Value) {
4374 glEnable(GL_SCISSOR_TEST);
4375 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4376 } else {
4377 glDisable(GL_SCISSOR_TEST);
4378 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4380 break;
4382 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4384 if(Value) {
4385 tmpvalue.d = Value;
4386 glEnable(GL_POLYGON_OFFSET_FILL);
4387 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4388 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4389 checkGLcall("glPolygonOffset(...)");
4390 } else {
4391 glDisable(GL_POLYGON_OFFSET_FILL);
4392 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4394 break;
4396 case WINED3DRS_ANTIALIASEDLINEENABLE :
4398 if(Value) {
4399 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4400 glEnable(GL_BLEND);
4401 checkGLcall("glEnable(GL_BLEND)");
4402 glEnable(GL_LINE_SMOOTH);
4403 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4404 } else {
4405 glDisable(GL_BLEND);
4406 checkGLcall("glDisable(GL_BLEND)");
4407 glDisable(GL_LINE_SMOOTH);
4408 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4410 break;
4412 case WINED3DRS_DEPTHBIAS :
4414 if(Value) {
4415 tmpvalue.d = Value;
4416 glEnable(GL_POLYGON_OFFSET_FILL);
4417 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4418 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4419 checkGLcall("glPolygonOffset(...)");
4420 } else {
4421 glDisable(GL_POLYGON_OFFSET_FILL);
4422 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4424 break;
4427 case WINED3DRS_TEXTUREPERSPECTIVE :
4429 if (Value)
4430 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4431 else
4432 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4433 break;
4436 case WINED3DRS_STIPPLEDALPHA :
4438 if (Value)
4439 ERR(" Stippled Alpha not supported yet.\n");
4440 break;
4442 case WINED3DRS_ANTIALIAS :
4444 if (Value)
4445 ERR(" Antialias not supported yet.\n");
4446 break;
4448 default:
4449 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4452 LEAVE_GL();
4454 return WINED3D_OK;
4457 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4459 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4460 *pValue = This->stateBlock->renderState[State];
4461 return WINED3D_OK;
4464 /*****
4465 * Get / Set Sampler States
4466 * TODO: Verify against dx9 definitions
4467 *****/
4469 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 * SetSampler is designed to allow for more than the standard up to 8 textures
4473 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4474 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4476 * http://developer.nvidia.com/object/General_FAQ.html#t6
4478 * There are two new settings for GForce
4479 * the sampler one:
4480 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4481 * and the texture one:
4482 * GL_MAX_TEXTURE_COORDS_ARB.
4483 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4484 ******************/
4485 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4486 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4487 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4488 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4489 return WINED3DERR_INVALIDCALL;
4492 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4493 debug_d3dsamplerstate(Type), Type, Value);
4494 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4495 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4496 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4498 /* Handle recording of state blocks */
4499 if (This->isRecordingState) {
4500 TRACE("Recording... not performing anything\n");
4501 return WINED3D_OK;
4504 return WINED3D_OK;
4507 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 /** TODO: check that sampler is in range **/
4510 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4511 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4513 return WINED3D_OK;
4516 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 ENTER_GL();
4520 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4521 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4522 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4523 LEAVE_GL();
4525 return WINED3D_OK;
4528 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 GLint scissorBox[4];
4532 ENTER_GL();
4533 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4534 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4535 pRect->left = scissorBox[0];
4536 pRect->top = scissorBox[1];
4537 pRect->right = scissorBox[0] + scissorBox[2];
4538 pRect->bottom = scissorBox[1] + scissorBox[3];
4539 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4540 LEAVE_GL();
4541 return WINED3D_OK;
4544 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4546 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4548 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4550 This->updateStateBlock->vertexDecl = pDecl;
4551 This->updateStateBlock->changed.vertexDecl = TRUE;
4552 This->updateStateBlock->set.vertexDecl = TRUE;
4554 if (This->isRecordingState) {
4555 TRACE("Recording... not performing anything\n");
4558 if (NULL != pDecl) {
4559 IWineD3DVertexDeclaration_AddRef(pDecl);
4561 if (NULL != oldDecl) {
4562 IWineD3DVertexDeclaration_Release(oldDecl);
4564 return WINED3D_OK;
4567 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4570 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4572 *ppDecl = This->stateBlock->vertexDecl;
4573 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4574 return WINED3D_OK;
4577 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4581 This->updateStateBlock->vertexShader = pShader;
4582 This->updateStateBlock->changed.vertexShader = TRUE;
4583 This->updateStateBlock->set.vertexShader = TRUE;
4585 if (This->isRecordingState) {
4586 TRACE("Recording... not performing anything\n");
4589 if (NULL != pShader) {
4590 IWineD3DVertexShader_AddRef(pShader);
4592 if (NULL != oldShader) {
4593 IWineD3DVertexShader_Release(oldShader);
4596 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4598 * TODO: merge HAL shaders context switching from prototype
4600 return WINED3D_OK;
4603 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4606 if (NULL == ppShader) {
4607 return WINED3DERR_INVALIDCALL;
4609 *ppShader = This->stateBlock->vertexShader;
4610 if( NULL != *ppShader)
4611 IWineD3DVertexShader_AddRef(*ppShader);
4613 TRACE("(%p) : returning %p\n", This, *ppShader);
4614 return WINED3D_OK;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4618 IWineD3DDevice *iface,
4619 UINT start,
4620 CONST BOOL *srcData,
4621 UINT count) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 int i, cnt = min(count, MAX_CONST_B - start);
4626 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4627 iface, srcData, start, count);
4629 if (srcData == NULL || cnt < 0)
4630 return WINED3DERR_INVALIDCALL;
4632 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4633 for (i = 0; i < cnt; i++)
4634 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4636 for (i = start; i < cnt + start; ++i) {
4637 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4638 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4641 return WINED3D_OK;
4644 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4645 IWineD3DDevice *iface,
4646 UINT start,
4647 BOOL *dstData,
4648 UINT count) {
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 int cnt = min(count, MAX_CONST_B - start);
4653 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4654 iface, dstData, start, count);
4656 if (dstData == NULL || cnt < 0)
4657 return WINED3DERR_INVALIDCALL;
4659 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4660 return WINED3D_OK;
4663 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4664 IWineD3DDevice *iface,
4665 UINT start,
4666 CONST int *srcData,
4667 UINT count) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 int i, cnt = min(count, MAX_CONST_I - start);
4672 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4673 iface, srcData, start, count);
4675 if (srcData == NULL || cnt < 0)
4676 return WINED3DERR_INVALIDCALL;
4678 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4679 for (i = 0; i < cnt; i++)
4680 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4681 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4683 for (i = start; i < cnt + start; ++i) {
4684 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4685 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4688 return WINED3D_OK;
4691 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4692 IWineD3DDevice *iface,
4693 UINT start,
4694 int *dstData,
4695 UINT count) {
4697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4698 int cnt = min(count, MAX_CONST_I - start);
4700 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4701 iface, dstData, start, count);
4703 if (dstData == NULL || cnt < 0)
4704 return WINED3DERR_INVALIDCALL;
4706 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4707 return WINED3D_OK;
4710 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4711 IWineD3DDevice *iface,
4712 UINT start,
4713 CONST float *srcData,
4714 UINT count) {
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4719 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4720 iface, srcData, start, count);
4722 if (srcData == NULL || cnt < 0)
4723 return WINED3DERR_INVALIDCALL;
4725 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4726 for (i = 0; i < cnt; i++)
4727 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4728 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4730 for (i = start; i < cnt + start; ++i) {
4731 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4732 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4735 return WINED3D_OK;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4739 IWineD3DDevice *iface,
4740 UINT start,
4741 float *dstData,
4742 UINT count) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4747 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4748 iface, dstData, start, count);
4750 if (dstData == NULL || cnt < 0)
4751 return WINED3DERR_INVALIDCALL;
4753 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4754 return WINED3D_OK;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4759 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4760 This->updateStateBlock->pixelShader = pShader;
4761 This->updateStateBlock->changed.pixelShader = TRUE;
4762 This->updateStateBlock->set.pixelShader = TRUE;
4764 /* Handle recording of state blocks */
4765 if (This->isRecordingState) {
4766 TRACE("Recording... not performing anything\n");
4769 if (NULL != pShader) {
4770 IWineD3DPixelShader_AddRef(pShader);
4772 if (NULL != oldShader) {
4773 IWineD3DPixelShader_Release(oldShader);
4776 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4778 * TODO: merge HAL shaders context switching from prototype
4780 return WINED3D_OK;
4783 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 if (NULL == ppShader) {
4787 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4788 return WINED3DERR_INVALIDCALL;
4791 *ppShader = This->stateBlock->pixelShader;
4792 if (NULL != *ppShader) {
4793 IWineD3DPixelShader_AddRef(*ppShader);
4795 TRACE("(%p) : returning %p\n", This, *ppShader);
4796 return WINED3D_OK;
4799 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4800 IWineD3DDevice *iface,
4801 UINT start,
4802 CONST BOOL *srcData,
4803 UINT count) {
4805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4806 int i, cnt = min(count, MAX_CONST_B - start);
4808 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4809 iface, srcData, start, count);
4811 if (srcData == NULL || cnt < 0)
4812 return WINED3DERR_INVALIDCALL;
4814 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4815 for (i = 0; i < cnt; i++)
4816 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4818 for (i = start; i < cnt + start; ++i) {
4819 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4820 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4823 return WINED3D_OK;
4826 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4827 IWineD3DDevice *iface,
4828 UINT start,
4829 BOOL *dstData,
4830 UINT count) {
4832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 int cnt = min(count, MAX_CONST_B - start);
4835 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4836 iface, dstData, start, count);
4838 if (dstData == NULL || cnt < 0)
4839 return WINED3DERR_INVALIDCALL;
4841 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4842 return WINED3D_OK;
4845 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4846 IWineD3DDevice *iface,
4847 UINT start,
4848 CONST int *srcData,
4849 UINT count) {
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4852 int i, cnt = min(count, MAX_CONST_I - start);
4854 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4855 iface, srcData, start, count);
4857 if (srcData == NULL || cnt < 0)
4858 return WINED3DERR_INVALIDCALL;
4860 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4861 for (i = 0; i < cnt; i++)
4862 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4863 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4865 for (i = start; i < cnt + start; ++i) {
4866 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4867 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4870 return WINED3D_OK;
4873 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4874 IWineD3DDevice *iface,
4875 UINT start,
4876 int *dstData,
4877 UINT count) {
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 int cnt = min(count, MAX_CONST_I - start);
4882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4883 iface, dstData, start, count);
4885 if (dstData == NULL || cnt < 0)
4886 return WINED3DERR_INVALIDCALL;
4888 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4889 return WINED3D_OK;
4892 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4893 IWineD3DDevice *iface,
4894 UINT start,
4895 CONST float *srcData,
4896 UINT count) {
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4901 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4902 iface, srcData, start, count);
4904 if (srcData == NULL || cnt < 0)
4905 return WINED3DERR_INVALIDCALL;
4907 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4908 for (i = 0; i < cnt; i++)
4909 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4910 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4912 for (i = start; i < cnt + start; ++i) {
4913 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4914 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4917 return WINED3D_OK;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4921 IWineD3DDevice *iface,
4922 UINT start,
4923 float *dstData,
4924 UINT count) {
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4927 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4929 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4930 iface, dstData, start, count);
4932 if (dstData == NULL || cnt < 0)
4933 return WINED3DERR_INVALIDCALL;
4935 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4936 return WINED3D_OK;
4939 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4940 static HRESULT
4941 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4942 char *dest_ptr, *dest_conv = NULL;
4943 unsigned int i;
4944 DWORD DestFVF = dest->fvf;
4945 D3DVIEWPORT9 vp;
4946 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4947 BOOL doClip;
4948 int numTextures;
4950 if (SrcFVF & D3DFVF_NORMAL) {
4951 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4954 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4955 ERR("Source has no position mask\n");
4956 return WINED3DERR_INVALIDCALL;
4959 /* We might access VBOs from this code, so hold the lock */
4960 ENTER_GL();
4962 if (dest->resource.allocatedMemory == NULL) {
4963 /* This may happen if we do direct locking into a vbo. Unlikely,
4964 * but theoretically possible(ddraw processvertices test)
4966 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4967 if(!dest->resource.allocatedMemory) {
4968 LEAVE_GL();
4969 ERR("Out of memory\n");
4970 return E_OUTOFMEMORY;
4972 if(dest->vbo) {
4973 void *src;
4974 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4975 checkGLcall("glBindBufferARB");
4976 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4977 if(src) {
4978 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4980 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4981 checkGLcall("glUnmapBufferARB");
4985 /* Get a pointer into the destination vbo(create one if none exists) and
4986 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4988 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4989 CreateVBO(dest);
4992 if(dest->vbo) {
4993 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4994 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4995 if(!dest_conv) {
4996 ERR("glMapBuffer failed\n");
4997 /* Continue without storing converted vertices */
5001 /* Should I clip?
5002 * a) D3DRS_CLIPPING is enabled
5003 * b) WINED3DVOP_CLIP is passed
5005 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5006 static BOOL warned = FALSE;
5008 * The clipping code is not quite correct. Some things need
5009 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5010 * so disable clipping for now.
5011 * (The graphics in Half-Life are broken, and my processvertices
5012 * test crashes with IDirect3DDevice3)
5013 doClip = TRUE;
5015 doClip = FALSE;
5016 if(!warned) {
5017 warned = TRUE;
5018 FIXME("Clipping is broken and disabled for now\n");
5020 } else doClip = FALSE;
5021 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5022 if(dest_conv) {
5023 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5026 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5027 D3DTS_VIEW,
5028 &view_mat);
5029 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5030 D3DTS_PROJECTION,
5031 &proj_mat);
5032 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5033 D3DTS_WORLDMATRIX(0),
5034 &world_mat);
5036 TRACE("View mat:\n");
5037 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); \
5038 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); \
5039 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); \
5040 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); \
5042 TRACE("Proj mat:\n");
5043 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); \
5044 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); \
5045 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); \
5046 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); \
5048 TRACE("World mat:\n");
5049 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); \
5050 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); \
5051 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); \
5052 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); \
5054 /* Get the viewport */
5055 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5056 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5057 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5059 multiply_matrix(&mat,&view_mat,&world_mat);
5060 multiply_matrix(&mat,&proj_mat,&mat);
5062 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5064 for (i = 0; i < dwCount; i+= 1) {
5065 unsigned int tex_index;
5067 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5068 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5069 /* The position first */
5070 float *p =
5071 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5072 float x, y, z, rhw;
5073 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5075 /* Multiplication with world, view and projection matrix */
5076 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);
5077 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);
5078 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);
5079 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);
5081 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5083 /* WARNING: The following things are taken from d3d7 and were not yet checked
5084 * against d3d8 or d3d9!
5087 /* Clipping conditions: From
5088 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5090 * A vertex is clipped if it does not match the following requirements
5091 * -rhw < x <= rhw
5092 * -rhw < y <= rhw
5093 * 0 < z <= rhw
5094 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5096 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5097 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5101 if( doClip == FALSE ||
5102 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5103 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5104 ( rhw > eps ) ) ) {
5106 /* "Normal" viewport transformation (not clipped)
5107 * 1) The values are divided by rhw
5108 * 2) The y axis is negative, so multiply it with -1
5109 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5110 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5111 * 4) Multiply x with Width/2 and add Width/2
5112 * 5) The same for the height
5113 * 6) Add the viewpoint X and Y to the 2D coordinates and
5114 * The minimum Z value to z
5115 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5117 * Well, basically it's simply a linear transformation into viewport
5118 * coordinates
5121 x /= rhw;
5122 y /= rhw;
5123 z /= rhw;
5125 y *= -1;
5127 x *= vp.Width / 2;
5128 y *= vp.Height / 2;
5129 z *= vp.MaxZ - vp.MinZ;
5131 x += vp.Width / 2 + vp.X;
5132 y += vp.Height / 2 + vp.Y;
5133 z += vp.MinZ;
5135 rhw = 1 / rhw;
5136 } else {
5137 /* That vertex got clipped
5138 * Contrary to OpenGL it is not dropped completely, it just
5139 * undergoes a different calculation.
5141 TRACE("Vertex got clipped\n");
5142 x += rhw;
5143 y += rhw;
5145 x /= 2;
5146 y /= 2;
5148 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5149 * outside of the main vertex buffer memory. That needs some more
5150 * investigation...
5154 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5157 ( (float *) dest_ptr)[0] = x;
5158 ( (float *) dest_ptr)[1] = y;
5159 ( (float *) dest_ptr)[2] = z;
5160 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5162 dest_ptr += 3 * sizeof(float);
5164 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5165 dest_ptr += sizeof(float);
5168 if(dest_conv) {
5169 float w = 1 / rhw;
5170 ( (float *) dest_conv)[0] = x * w;
5171 ( (float *) dest_conv)[1] = y * w;
5172 ( (float *) dest_conv)[2] = z * w;
5173 ( (float *) dest_conv)[3] = w;
5175 dest_conv += 3 * sizeof(float);
5177 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5178 dest_conv += sizeof(float);
5182 if (DestFVF & D3DFVF_PSIZE) {
5183 dest_ptr += sizeof(DWORD);
5184 if(dest_conv) dest_conv += sizeof(DWORD);
5186 if (DestFVF & D3DFVF_NORMAL) {
5187 float *normal =
5188 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5189 /* AFAIK this should go into the lighting information */
5190 FIXME("Didn't expect the destination to have a normal\n");
5191 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5192 if(dest_conv) {
5193 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5197 if (DestFVF & D3DFVF_DIFFUSE) {
5198 DWORD *color_d =
5199 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5200 if(!color_d) {
5201 static BOOL warned = FALSE;
5203 if(warned == FALSE) {
5204 ERR("No diffuse color in source, but destination has one\n");
5205 warned = TRUE;
5208 *( (DWORD *) dest_ptr) = 0xffffffff;
5209 dest_ptr += sizeof(DWORD);
5211 if(dest_conv) {
5212 *( (DWORD *) dest_conv) = 0xffffffff;
5213 dest_conv += sizeof(DWORD);
5216 else {
5217 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5218 if(dest_conv) {
5219 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5220 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5221 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5222 dest_conv += sizeof(DWORD);
5227 if (DestFVF & D3DFVF_SPECULAR) {
5228 /* What's the color value in the feedback buffer? */
5229 DWORD *color_s =
5230 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5231 if(!color_s) {
5232 static BOOL warned = FALSE;
5234 if(warned == FALSE) {
5235 ERR("No specular color in source, but destination has one\n");
5236 warned = TRUE;
5239 *( (DWORD *) dest_ptr) = 0xFF000000;
5240 dest_ptr += sizeof(DWORD);
5242 if(dest_conv) {
5243 *( (DWORD *) dest_conv) = 0xFF000000;
5244 dest_conv += sizeof(DWORD);
5247 else {
5248 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5249 if(dest_conv) {
5250 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5251 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5252 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5253 dest_conv += sizeof(DWORD);
5258 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5259 float *tex_coord =
5260 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5261 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5262 if(!tex_coord) {
5263 ERR("No source texture, but destination requests one\n");
5264 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5265 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5267 else {
5268 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5269 if(dest_conv) {
5270 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5276 if(dest_conv) {
5277 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5278 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5281 LEAVE_GL();
5283 return WINED3D_OK;
5285 #undef copy_and_next
5287 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5290 WineDirect3DVertexStridedData strided;
5291 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5293 /* We don't need the source vbo because this buffer is only used as
5294 * a source for ProcessVertices. Avoid wasting resources by converting the
5295 * buffer and loading the VBO
5297 if(SrcImpl->vbo) {
5298 TRACE("Releaseing the source vbo, it won't be needed\n");
5300 if(!SrcImpl->resource.allocatedMemory) {
5301 /* Rescue the data from the buffer */
5302 void *src;
5303 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5304 if(!SrcImpl->resource.allocatedMemory) {
5305 ERR("Out of memory\n");
5306 return E_OUTOFMEMORY;
5309 ENTER_GL();
5310 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5311 checkGLcall("glBindBufferARB");
5313 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5314 if(src) {
5315 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5318 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5319 checkGLcall("glUnmapBufferARB");
5320 } else {
5321 ENTER_GL();
5324 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5325 checkGLcall("glBindBufferARB");
5326 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5327 checkGLcall("glDeleteBuffersARB");
5328 LEAVE_GL();
5330 SrcImpl->vbo = 0;
5333 memset(&strided, 0, sizeof(strided));
5334 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5336 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5339 /*****
5340 * Apply / Get / Set Texture Stage States
5341 * TODO: Verify against dx9 definitions
5342 *****/
5344 /* 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 */
5345 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5347 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5348 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5350 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5352 /* Check that the stage is within limits */
5353 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5354 TRACE("Attempt to access invalid texture rejected\n");
5355 return;
5358 ENTER_GL();
5360 switch (Type) {
5361 case WINED3DTSS_ALPHAOP :
5362 case WINED3DTSS_COLOROP :
5363 /* nothing to do as moved to drawprim for now */
5364 break;
5365 case WINED3DTSS_ADDRESSW :
5366 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5367 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5368 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5370 } else {
5371 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5372 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5373 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5374 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5376 #endif
5377 case WINED3DTSS_TEXCOORDINDEX :
5379 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5381 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5382 one flag, you can still specify an index value, which the system uses to
5383 determine the texture wrapping mode.
5384 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5385 means use the vertex position (camera-space) as the input texture coordinates
5386 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5387 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5388 to the TEXCOORDINDEX value */
5391 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5393 switch (Value & 0xFFFF0000) {
5394 case D3DTSS_TCI_PASSTHRU:
5395 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5396 glDisable(GL_TEXTURE_GEN_S);
5397 glDisable(GL_TEXTURE_GEN_T);
5398 glDisable(GL_TEXTURE_GEN_R);
5399 glDisable(GL_TEXTURE_GEN_Q);
5400 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5401 break;
5403 case D3DTSS_TCI_CAMERASPACEPOSITION:
5404 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5405 as the input texture coordinates for this stage's texture transformation. This
5406 equates roughly to EYE_LINEAR */
5408 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5409 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5410 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5411 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5412 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5414 glMatrixMode(GL_MODELVIEW);
5415 glPushMatrix();
5416 glLoadIdentity();
5417 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5418 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5419 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5420 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5421 glPopMatrix();
5423 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5424 glEnable(GL_TEXTURE_GEN_S);
5425 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5426 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5427 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5428 glEnable(GL_TEXTURE_GEN_T);
5429 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5430 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5431 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5432 glEnable(GL_TEXTURE_GEN_R);
5433 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5434 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5435 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5437 break;
5439 case D3DTSS_TCI_CAMERASPACENORMAL:
5441 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5442 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5443 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5444 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5445 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5446 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5448 glMatrixMode(GL_MODELVIEW);
5449 glPushMatrix();
5450 glLoadIdentity();
5451 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5452 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5453 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5454 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5455 glPopMatrix();
5457 glEnable(GL_TEXTURE_GEN_S);
5458 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5459 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5460 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5461 glEnable(GL_TEXTURE_GEN_T);
5462 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5463 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5464 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5465 glEnable(GL_TEXTURE_GEN_R);
5466 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5467 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5468 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5471 break;
5473 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5475 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5476 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5477 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5478 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5479 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5480 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5482 glMatrixMode(GL_MODELVIEW);
5483 glPushMatrix();
5484 glLoadIdentity();
5485 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5486 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5487 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5488 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5489 glPopMatrix();
5491 glEnable(GL_TEXTURE_GEN_S);
5492 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5493 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5494 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5495 glEnable(GL_TEXTURE_GEN_T);
5496 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5497 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5498 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5499 glEnable(GL_TEXTURE_GEN_R);
5500 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5501 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5502 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5505 break;
5507 /* Unhandled types: */
5508 default:
5509 /* Todo: */
5510 /* ? disable GL_TEXTURE_GEN_n ? */
5511 glDisable(GL_TEXTURE_GEN_S);
5512 glDisable(GL_TEXTURE_GEN_T);
5513 glDisable(GL_TEXTURE_GEN_R);
5514 glDisable(GL_TEXTURE_GEN_Q);
5515 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5516 break;
5519 break;
5521 /* Unhandled */
5522 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5523 set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5524 break;
5526 case WINED3DTSS_BUMPENVMAT00 :
5527 case WINED3DTSS_BUMPENVMAT01 :
5528 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5529 break;
5530 case WINED3DTSS_BUMPENVMAT10 :
5531 case WINED3DTSS_BUMPENVMAT11 :
5532 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5533 break;
5535 case WINED3DTSS_BUMPENVLSCALE :
5536 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5537 break;
5539 case WINED3DTSS_BUMPENVLOFFSET :
5540 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5541 break;
5543 case WINED3DTSS_RESULTARG :
5544 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5545 break;
5547 default:
5548 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5549 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5552 LEAVE_GL();
5554 return;
5557 /*****
5558 * Get / Set Texture Stage States
5559 * TODO: Verify against dx9 definitions
5560 *****/
5561 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5564 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5566 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5568 /* Reject invalid texture units */
5569 if (Stage >= GL_LIMITS(texture_stages)) {
5570 TRACE("Attempt to access invalid texture rejected\n");
5571 return WINED3DERR_INVALIDCALL;
5574 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5575 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5576 This->updateStateBlock->textureState[Stage][Type] = Value;
5578 return WINED3D_OK;
5581 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5584 *pValue = This->updateStateBlock->textureState[Stage][Type];
5585 return WINED3D_OK;
5588 /*****
5589 * Get / Set Texture
5590 *****/
5591 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5594 IWineD3DBaseTexture *oldTexture;
5596 oldTexture = This->updateStateBlock->textures[Stage];
5597 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5599 #if 0 /* TODO: check so vertex textures */
5600 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5601 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5602 return WINED3D_OK;
5604 #endif
5606 /* Reject invalid texture units */
5607 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5608 WARN("Attempt to access invalid texture rejected\n");
5609 return WINED3DERR_INVALIDCALL;
5612 if(pTexture != NULL) {
5613 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5615 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5616 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5617 return WINED3DERR_INVALIDCALL;
5621 oldTexture = This->updateStateBlock->textures[Stage];
5622 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5623 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5625 This->updateStateBlock->set.textures[Stage] = TRUE;
5626 This->updateStateBlock->changed.textures[Stage] = TRUE;
5627 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5628 This->updateStateBlock->textures[Stage] = pTexture;
5630 /* Handle recording of state blocks */
5631 if (This->isRecordingState) {
5632 TRACE("Recording... not performing anything\n");
5633 return WINED3D_OK;
5636 /** NOTE: MSDN says that setTexture increases the reference count,
5637 * and the the application nust set the texture back to null (or have a leaky application),
5638 * This means we should pass the refcount up to the parent
5639 *******************************/
5640 if (NULL != This->updateStateBlock->textures[Stage]) {
5641 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5644 if (NULL != oldTexture) {
5645 IWineD3DBaseTexture_Release(oldTexture);
5648 /* Reset color keying */
5649 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5650 BOOL enable_ckey = FALSE;
5652 if(pTexture) {
5653 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5654 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5657 if(enable_ckey) {
5658 glAlphaFunc(GL_NOTEQUAL, 0.0);
5659 checkGLcall("glAlphaFunc");
5663 return WINED3D_OK;
5666 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5670 /* Reject invalid texture units */
5671 if (Stage >= GL_LIMITS(sampler_stages)) {
5672 TRACE("Attempt to access invalid texture rejected\n");
5673 return WINED3DERR_INVALIDCALL;
5675 *ppTexture=This->updateStateBlock->textures[Stage];
5676 if (*ppTexture)
5677 IWineD3DBaseTexture_AddRef(*ppTexture);
5678 else
5679 return WINED3DERR_INVALIDCALL;
5680 return WINED3D_OK;
5683 /*****
5684 * Get Back Buffer
5685 *****/
5686 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5687 IWineD3DSurface **ppBackBuffer) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 IWineD3DSwapChain *swapChain;
5690 HRESULT hr;
5692 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5694 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5695 if (hr == WINED3D_OK) {
5696 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5697 IWineD3DSwapChain_Release(swapChain);
5698 } else {
5699 *ppBackBuffer = NULL;
5701 return hr;
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 WARN("(%p) : stub, calling idirect3d for now\n", This);
5707 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5710 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 IWineD3DSwapChain *swapChain;
5713 HRESULT hr;
5715 if(iSwapChain > 0) {
5716 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5717 if (hr == WINED3D_OK) {
5718 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5719 IWineD3DSwapChain_Release(swapChain);
5720 } else {
5721 FIXME("(%p) Error getting display mode\n", This);
5723 } else {
5724 /* Don't read the real display mode,
5725 but return the stored mode instead. X11 can't change the color
5726 depth, and some apps are pretty angry if they SetDisplayMode from
5727 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5729 Also don't relay to the swapchain because with ddraw it's possible
5730 that there isn't a swapchain at all */
5731 pMode->Width = This->ddraw_width;
5732 pMode->Height = This->ddraw_height;
5733 pMode->Format = This->ddraw_format;
5734 pMode->RefreshRate = 0;
5735 hr = WINED3D_OK;
5738 return hr;
5741 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5743 TRACE("(%p)->(%p)\n", This, hWnd);
5745 This->ddraw_window = hWnd;
5746 return WINED3D_OK;
5749 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5751 TRACE("(%p)->(%p)\n", This, hWnd);
5753 *hWnd = This->ddraw_window;
5754 return WINED3D_OK;
5757 /*****
5758 * Stateblock related functions
5759 *****/
5761 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5763 IWineD3DStateBlockImpl *object;
5764 HRESULT temp_result;
5766 TRACE("(%p)", This);
5768 if (This->isRecordingState) {
5769 return WINED3DERR_INVALIDCALL;
5772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5773 if (NULL == object ) {
5774 FIXME("(%p)Error allocating memory for stateblock\n", This);
5775 return E_OUTOFMEMORY;
5777 TRACE("(%p) created object %p\n", This, object);
5778 object->wineD3DDevice= This;
5779 /** FIXME: object->parent = parent; **/
5780 object->parent = NULL;
5781 object->blockType = WINED3DSBT_ALL;
5782 object->ref = 1;
5783 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5785 temp_result = allocate_shader_constants(object);
5786 if (WINED3D_OK != temp_result)
5787 return temp_result;
5789 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5790 This->updateStateBlock = object;
5791 This->isRecordingState = TRUE;
5793 TRACE("(%p) recording stateblock %p\n",This , object);
5794 return WINED3D_OK;
5797 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 if (!This->isRecordingState) {
5801 FIXME("(%p) not recording! returning error\n", This);
5802 *ppStateBlock = NULL;
5803 return WINED3DERR_INVALIDCALL;
5806 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5807 This->isRecordingState = FALSE;
5808 This->updateStateBlock = This->stateBlock;
5809 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5810 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5811 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5812 return WINED3D_OK;
5815 /*****
5816 * Scene related functions
5817 *****/
5818 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5819 /* At the moment we have no need for any functionality at the beginning
5820 of a scene */
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 TRACE("(%p) : stub\n", This);
5823 return WINED3D_OK;
5826 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5828 TRACE("(%p)\n", This);
5829 ENTER_GL();
5830 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5831 glFlush();
5832 checkGLcall("glFlush");
5834 TRACE("End Scene\n");
5835 if(This->renderTarget != NULL) {
5837 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5838 IUnknown *targetContainer = NULL;
5839 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5840 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5841 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5842 /** always dirtify for now. we must find a better way to see that surface have been modified
5843 (Modifications should will only occur via draw-primitive, but we do need better locking
5844 switching to render-to-texture should remove the overhead though.
5846 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5847 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5848 IWineD3DSurface_PreLoad(This->renderTarget);
5849 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5850 IUnknown_Release(targetContainer);
5853 This->sceneEnded = TRUE;
5854 LEAVE_GL();
5855 return WINED3D_OK;
5858 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5859 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5860 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5862 IWineD3DSwapChain *swapChain = NULL;
5863 int i;
5864 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5866 TRACE("(%p) Presenting the frame\n", This);
5868 for(i = 0 ; i < swapchains ; i ++) {
5870 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5871 TRACE("presentinng chain %d, %p\n", i, swapChain);
5872 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5873 IWineD3DSwapChain_Release(swapChain);
5876 return WINED3D_OK;
5879 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5880 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5883 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5884 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5885 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5886 GLbitfield glMask = 0;
5887 GLboolean old_ztest;
5888 GLfloat old_z_clear_value;
5889 GLint old_stencil_clear_value;
5890 GLfloat old_color_clear_value[4];
5891 unsigned int i;
5892 CONST D3DRECT* curRect;
5894 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5895 Count, pRects, Flags, Z, Stencil);
5897 ENTER_GL();
5899 glEnable(GL_SCISSOR_TEST);
5900 checkGLcall("glEnable GL_SCISSOR_TEST");
5902 if (Count > 0 && pRects) {
5903 curRect = pRects;
5904 } else {
5905 curRect = NULL;
5908 /* Only set the values up once, as they are not changing */
5909 if (Flags & D3DCLEAR_STENCIL) {
5910 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5911 glClearStencil(Stencil);
5912 checkGLcall("glClearStencil");
5913 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5914 glStencilMask(0xFFFFFFFF);
5917 if (Flags & D3DCLEAR_ZBUFFER) {
5918 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5919 glDepthMask(GL_TRUE);
5920 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5921 glClearDepth(Z);
5922 checkGLcall("glClearDepth");
5923 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5926 if (Flags & D3DCLEAR_TARGET) {
5927 TRACE("Clearing screen with glClear to color %lx\n", Color);
5928 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5929 glClearColor(D3DCOLOR_R(Color),
5930 D3DCOLOR_G(Color),
5931 D3DCOLOR_B(Color),
5932 D3DCOLOR_A(Color));
5933 checkGLcall("glClearColor");
5935 /* Clear ALL colors! */
5936 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5937 glMask = glMask | GL_COLOR_BUFFER_BIT;
5940 /* Now process each rect in turn */
5941 for (i = 0; i < Count || i == 0; i++) {
5943 if (curRect) {
5944 /* Note gl uses lower left, width/height */
5945 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5946 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5947 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5948 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5949 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5950 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5951 checkGLcall("glScissor");
5952 } else {
5953 glScissor(This->stateBlock->viewport.X,
5954 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5955 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5956 This->stateBlock->viewport.Width,
5957 This->stateBlock->viewport.Height);
5958 checkGLcall("glScissor");
5961 /* Clear the selected rectangle (or full screen) */
5962 glClear(glMask);
5963 checkGLcall("glClear");
5965 /* Step to the next rectangle */
5966 if (curRect) curRect = curRect + sizeof(D3DRECT);
5969 /* Restore the old values (why..?) */
5970 if (Flags & D3DCLEAR_STENCIL) {
5971 glClearStencil(old_stencil_clear_value);
5972 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5974 if (Flags & D3DCLEAR_ZBUFFER) {
5975 glDepthMask(old_ztest);
5976 glClearDepth(old_z_clear_value);
5978 if (Flags & D3DCLEAR_TARGET) {
5979 glClearColor(old_color_clear_value[0],
5980 old_color_clear_value[1],
5981 old_color_clear_value[2],
5982 old_color_clear_value[3]);
5983 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5984 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5985 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5986 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5989 glDisable(GL_SCISSOR_TEST);
5990 checkGLcall("glDisable");
5991 LEAVE_GL();
5993 return WINED3D_OK;
5996 /*****
5997 * Drawing functions
5998 *****/
5999 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6000 UINT PrimitiveCount) {
6002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6003 This->stateBlock->streamIsUP = FALSE;
6005 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6006 debug_d3dprimitivetype(PrimitiveType),
6007 StartVertex, PrimitiveCount);
6008 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6009 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6012 return WINED3D_OK;
6015 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6016 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6017 D3DPRIMITIVETYPE PrimitiveType,
6018 INT baseVIndex, UINT minIndex,
6019 UINT NumVertices, UINT startIndex, UINT primCount) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6022 UINT idxStride = 2;
6023 IWineD3DIndexBuffer *pIB;
6024 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6026 pIB = This->stateBlock->pIndexData;
6027 This->stateBlock->streamIsUP = FALSE;
6029 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6030 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6031 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6033 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6034 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6035 idxStride = 2;
6036 } else {
6037 idxStride = 4;
6040 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6041 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6043 return WINED3D_OK;
6046 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6047 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6048 UINT VertexStreamZeroStride) {
6049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6051 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6052 debug_d3dprimitivetype(PrimitiveType),
6053 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6055 /* release the stream source */
6056 if (This->stateBlock->streamSource[0] != NULL) {
6057 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6060 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6061 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6062 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6063 This->stateBlock->streamIsUP = TRUE;
6065 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6066 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6068 /* MSDN specifies stream zero settings must be set to NULL */
6069 This->stateBlock->streamStride[0] = 0;
6070 This->stateBlock->streamSource[0] = NULL;
6072 /*stream zero settings set to null at end, as per the msdn */
6073 return WINED3D_OK;
6076 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6077 UINT MinVertexIndex, UINT NumVertices,
6078 UINT PrimitiveCount, CONST void* pIndexData,
6079 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6080 UINT VertexStreamZeroStride) {
6081 int idxStride;
6082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6084 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6085 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6086 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6087 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6089 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6090 idxStride = 2;
6091 } else {
6092 idxStride = 4;
6095 /* release the stream and index data */
6096 if (This->stateBlock->streamSource[0] != NULL) {
6097 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6099 if (This->stateBlock->pIndexData) {
6100 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6103 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6104 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6105 This->stateBlock->streamIsUP = TRUE;
6106 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6108 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6110 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6111 This->stateBlock->streamSource[0] = NULL;
6112 This->stateBlock->streamStride[0] = 0;
6113 This->stateBlock->pIndexData = NULL;
6115 return WINED3D_OK;
6118 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6120 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6121 return WINED3D_OK;
6123 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6124 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6126 HRESULT hr = WINED3D_OK;
6127 WINED3DRESOURCETYPE sourceType;
6128 WINED3DRESOURCETYPE destinationType;
6129 int i ,levels;
6131 /* TODO: think about moving the code into IWineD3DBaseTexture */
6133 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6135 /* verify that the source and destination textures aren't NULL */
6136 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6137 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6138 This, pSourceTexture, pDestinationTexture);
6139 hr = WINED3DERR_INVALIDCALL;
6142 if (pSourceTexture == pDestinationTexture) {
6143 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6144 This, pSourceTexture, pDestinationTexture);
6145 hr = WINED3DERR_INVALIDCALL;
6147 /* Verify that the source and destination textures are the same type */
6148 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6149 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6151 if (sourceType != destinationType) {
6152 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6153 This);
6154 hr = WINED3DERR_INVALIDCALL;
6157 /* check that both textures have the identical numbers of levels */
6158 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6159 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6160 hr = WINED3DERR_INVALIDCALL;
6163 if (WINED3D_OK == hr) {
6165 /* Make sure that the destination texture is loaded */
6166 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6168 /* Update every surface level of the texture */
6169 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6171 switch (sourceType) {
6172 case WINED3DRTYPE_TEXTURE:
6174 IWineD3DSurface *srcSurface;
6175 IWineD3DSurface *destSurface;
6177 for (i = 0 ; i < levels ; ++i) {
6178 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6179 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6180 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6181 IWineD3DSurface_Release(srcSurface);
6182 IWineD3DSurface_Release(destSurface);
6183 if (WINED3D_OK != hr) {
6184 WARN("(%p) : Call to update surface failed\n", This);
6185 return hr;
6189 break;
6190 case WINED3DRTYPE_CUBETEXTURE:
6192 IWineD3DSurface *srcSurface;
6193 IWineD3DSurface *destSurface;
6194 WINED3DCUBEMAP_FACES faceType;
6196 for (i = 0 ; i < levels ; ++i) {
6197 /* Update each cube face */
6198 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6199 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6200 if (WINED3D_OK != hr) {
6201 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6202 } else {
6203 TRACE("Got srcSurface %p\n", srcSurface);
6205 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6206 if (WINED3D_OK != hr) {
6207 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6208 } else {
6209 TRACE("Got desrSurface %p\n", destSurface);
6211 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6212 IWineD3DSurface_Release(srcSurface);
6213 IWineD3DSurface_Release(destSurface);
6214 if (WINED3D_OK != hr) {
6215 WARN("(%p) : Call to update surface failed\n", This);
6216 return hr;
6221 break;
6222 #if 0 /* TODO: Add support for volume textures */
6223 case WINED3DRTYPE_VOLUMETEXTURE:
6225 IWineD3DVolume srcVolume = NULL;
6226 IWineD3DSurface destVolume = NULL;
6228 for (i = 0 ; i < levels ; ++i) {
6229 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6230 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6231 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6232 IWineD3DVolume_Release(srcSurface);
6233 IWineD3DVolume_Release(destSurface);
6234 if (WINED3D_OK != hr) {
6235 WARN("(%p) : Call to update volume failed\n", This);
6236 return hr;
6240 break;
6241 #endif
6242 default:
6243 FIXME("(%p) : Unsupported source and destination type\n", This);
6244 hr = WINED3DERR_INVALIDCALL;
6248 return hr;
6251 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6252 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6253 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6256 TRACE("(%p) : stub\n", This);
6257 return WINED3D_OK;
6259 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6261 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6262 * NOTE It may be best to move the code into surface to occomplish this
6263 ****************************************/
6265 WINED3DSURFACE_DESC surfaceDesc;
6266 unsigned int surfaceWidth, surfaceHeight;
6267 glDescriptor *targetGlDescription = NULL;
6268 glDescriptor *surfaceGlDescription = NULL;
6269 IWineD3DSwapChainImpl *container = NULL;
6271 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6272 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6273 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6275 surfaceDesc.Width = &surfaceWidth;
6276 surfaceDesc.Height = &surfaceHeight;
6277 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6278 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6280 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6281 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6282 ENTER_GL();
6283 /* TODO: opengl Context switching for swapchains etc... */
6284 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6285 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6286 glReadBuffer(GL_BACK);
6287 vcheckGLcall("glReadBuffer(GL_BACK)");
6288 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6289 glReadBuffer(GL_FRONT);
6290 vcheckGLcall("glReadBuffer(GL_FRONT)");
6291 } else if (pRenderTarget == This->depthStencilBuffer) {
6292 FIXME("Reading of depthstencil not yet supported\n");
6295 glReadPixels(surfaceGlDescription->target,
6296 surfaceGlDescription->level,
6297 surfaceWidth,
6298 surfaceHeight,
6299 surfaceGlDescription->glFormat,
6300 surfaceGlDescription->glType,
6301 (void *)IWineD3DSurface_GetData(pSurface));
6302 vcheckGLcall("glReadPixels(...)");
6303 if(NULL != container ){
6304 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6306 } else {
6307 IWineD3DBaseTexture *container;
6308 GLenum textureDimensions = GL_TEXTURE_2D;
6310 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6311 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6312 IWineD3DBaseTexture_Release(container);
6314 /* TODO: 2D -> Cube surface coppies etc.. */
6315 if (surfaceGlDescription->target != textureDimensions) {
6316 FIXME("(%p) : Texture dimension mismatch\n", This);
6318 glEnable(textureDimensions);
6319 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6320 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6321 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6322 vcheckGLcall("glBindTexture");
6323 glGetTexImage(surfaceGlDescription->target,
6324 surfaceGlDescription->level,
6325 surfaceGlDescription->glFormat,
6326 surfaceGlDescription->glType,
6327 (void *)IWineD3DSurface_GetData(pSurface));
6328 glDisable(textureDimensions);
6329 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6332 LEAVE_GL();
6333 return WINED3D_OK;
6336 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6337 IWineD3DSwapChain *swapChain;
6338 HRESULT hr;
6339 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6340 if(hr == WINED3D_OK) {
6341 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6342 IWineD3DSwapChain_Release(swapChain);
6344 return hr;
6347 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6349 /* return a sensible default */
6350 *pNumPasses = 1;
6351 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6352 FIXME("(%p) : stub\n", This);
6353 return WINED3D_OK;
6356 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6358 int j;
6359 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6360 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6361 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6362 return WINED3DERR_INVALIDCALL;
6364 for (j = 0; j < 256; ++j) {
6365 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6366 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6367 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6368 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6370 TRACE("(%p) : returning\n", This);
6371 return WINED3D_OK;
6374 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6376 int j;
6377 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6378 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6379 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6380 return WINED3DERR_INVALIDCALL;
6382 for (j = 0; j < 256; ++j) {
6383 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6384 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6385 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6386 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6388 TRACE("(%p) : returning\n", This);
6389 return WINED3D_OK;
6392 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6394 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6395 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6396 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6397 return WINED3DERR_INVALIDCALL;
6399 /*TODO: stateblocks */
6400 This->currentPalette = PaletteNumber;
6401 TRACE("(%p) : returning\n", This);
6402 return WINED3D_OK;
6405 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6407 if (PaletteNumber == NULL) {
6408 WARN("(%p) : returning Invalid Call\n", This);
6409 return WINED3DERR_INVALIDCALL;
6411 /*TODO: stateblocks */
6412 *PaletteNumber = This->currentPalette;
6413 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6414 return WINED3D_OK;
6417 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6419 static BOOL showFixmes = TRUE;
6420 if (showFixmes) {
6421 FIXME("(%p) : stub\n", This);
6422 showFixmes = FALSE;
6425 This->softwareVertexProcessing = bSoftware;
6426 return WINED3D_OK;
6430 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 static BOOL showFixmes = TRUE;
6433 if (showFixmes) {
6434 FIXME("(%p) : stub\n", This);
6435 showFixmes = FALSE;
6437 return This->softwareVertexProcessing;
6441 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6443 IWineD3DSwapChain *swapChain;
6444 HRESULT hr;
6446 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6448 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6449 if(hr == WINED3D_OK){
6450 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6451 IWineD3DSwapChain_Release(swapChain);
6452 }else{
6453 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6455 return hr;
6459 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6461 static BOOL showfixmes = TRUE;
6462 if(nSegments != 0.0f) {
6463 if( showfixmes) {
6464 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6465 showfixmes = FALSE;
6468 return WINED3D_OK;
6471 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6473 static BOOL showfixmes = TRUE;
6474 if( showfixmes) {
6475 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6476 showfixmes = FALSE;
6478 return 0.0f;
6481 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6483 /** TODO: remove casts to IWineD3DSurfaceImpl
6484 * NOTE: move code to surface to accomplish this
6485 ****************************************/
6486 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6487 int srcWidth, srcHeight;
6488 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6489 WINED3DFORMAT destFormat, srcFormat;
6490 UINT destSize;
6491 int destLeft, destTop;
6492 WINED3DPOOL srcPool, destPool;
6493 int offset = 0;
6494 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6495 glDescriptor *glDescription = NULL;
6496 GLenum textureDimensions = GL_TEXTURE_2D;
6497 IWineD3DBaseTexture *baseTexture;
6499 WINED3DSURFACE_DESC winedesc;
6501 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6502 memset(&winedesc, 0, sizeof(winedesc));
6503 winedesc.Width = &srcSurfaceWidth;
6504 winedesc.Height = &srcSurfaceHeight;
6505 winedesc.Pool = &srcPool;
6506 winedesc.Format = &srcFormat;
6508 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6510 winedesc.Width = &destSurfaceWidth;
6511 winedesc.Height = &destSurfaceHeight;
6512 winedesc.Pool = &destPool;
6513 winedesc.Format = &destFormat;
6514 winedesc.Size = &destSize;
6516 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6518 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6519 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6520 return WINED3DERR_INVALIDCALL;
6523 if (destFormat == WINED3DFMT_UNKNOWN) {
6524 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6525 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6527 /* Get the update surface description */
6528 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6531 /* Make sure the surface is loaded and up to date */
6532 IWineD3DSurface_PreLoad(pDestinationSurface);
6534 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6536 ENTER_GL();
6538 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6539 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6540 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6541 destLeft = pDestPoint ? pDestPoint->x : 0;
6542 destTop = pDestPoint ? pDestPoint->y : 0;
6545 /* This function doesn't support compressed textures
6546 the pitch is just bytesPerPixel * width */
6547 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6548 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6549 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6550 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6552 /* TODO DXT formats */
6554 if(pSourceRect != NULL && pSourceRect->top != 0){
6555 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6557 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6558 ,This
6559 ,glDescription->level
6560 ,destLeft
6561 ,destTop
6562 ,srcWidth
6563 ,srcHeight
6564 ,glDescription->glFormat
6565 ,glDescription->glType
6566 ,IWineD3DSurface_GetData(pSourceSurface)
6569 /* Sanity check */
6570 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6572 /* need to lock the surface to get the data */
6573 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6576 /* TODO: Cube and volume support */
6577 if(rowoffset != 0){
6578 /* not a whole row so we have to do it a line at a time */
6579 int j;
6581 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6582 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6584 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6586 glTexSubImage2D(glDescription->target
6587 ,glDescription->level
6588 ,destLeft
6590 ,srcWidth
6592 ,glDescription->glFormat
6593 ,glDescription->glType
6594 ,data /* could be quicker using */
6596 data += rowoffset;
6599 } else { /* Full width, so just write out the whole texture */
6601 if (WINED3DFMT_DXT1 == destFormat ||
6602 WINED3DFMT_DXT2 == destFormat ||
6603 WINED3DFMT_DXT3 == destFormat ||
6604 WINED3DFMT_DXT4 == destFormat ||
6605 WINED3DFMT_DXT5 == destFormat) {
6606 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6607 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6608 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6609 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6610 } if (destFormat != srcFormat) {
6611 FIXME("Updating mixed format compressed texture is not curretly support\n");
6612 } else {
6613 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6614 glDescription->level,
6615 glDescription->glFormatInternal,
6616 srcWidth,
6617 srcHeight,
6619 destSize,
6620 IWineD3DSurface_GetData(pSourceSurface));
6622 } else {
6623 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6627 } else {
6628 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6630 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6631 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6632 data returned by GetData non-power2 width/height with hardware non-power2
6633 pow2Width/height are set to surface width height, repacking isn't needed so it
6634 doesn't matter which function gets called. */
6635 glTexSubImage2D(glDescription->target
6636 ,glDescription->level
6637 ,destLeft
6638 ,destTop
6639 ,srcWidth
6640 ,srcHeight
6641 ,glDescription->glFormat
6642 ,glDescription->glType
6643 ,IWineD3DSurface_GetData(pSourceSurface)
6645 } else {
6647 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6648 glTexSubImage2D(glDescription->target
6649 ,glDescription->level
6650 ,destLeft
6651 ,destTop
6652 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6653 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6654 ,glDescription->glFormat
6655 ,glDescription->glType
6656 ,IWineD3DSurface_GetData(pSourceSurface)
6662 checkGLcall("glTexSubImage2D");
6664 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6665 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6666 * surface bigger than it needs to be hmm.. */
6667 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6668 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6669 IWineD3DBaseTexture_Release(baseTexture);
6672 glDisable(textureDimensions); /* This needs to be managed better.... */
6673 LEAVE_GL();
6675 return WINED3D_OK;
6678 /* Used by DirectX 8 */
6679 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6680 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6681 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6684 HRESULT hr = WINED3D_OK;
6685 WINED3DFORMAT srcFormat, destFormat;
6686 UINT srcWidth, destWidth;
6687 UINT srcHeight, destHeight;
6688 UINT srcSize;
6689 WINED3DSURFACE_DESC winedesc;
6691 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6692 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6695 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6696 memset(&winedesc, 0, sizeof(winedesc));
6698 winedesc.Format = &srcFormat;
6699 winedesc.Width = &srcWidth;
6700 winedesc.Height = &srcHeight;
6701 winedesc.Size = &srcSize;
6702 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6704 winedesc.Format = &destFormat;
6705 winedesc.Width = &destWidth;
6706 winedesc.Height = &destHeight;
6707 winedesc.Size = NULL;
6708 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6710 /* Check that the source and destination formats match */
6711 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6712 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6713 return WINED3DERR_INVALIDCALL;
6714 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6715 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6716 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6717 destFormat = srcFormat;
6720 /* Quick if complete copy ... */
6721 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6723 if (srcWidth == destWidth && srcHeight == destHeight) {
6724 WINED3DLOCKED_RECT lrSrc;
6725 WINED3DLOCKED_RECT lrDst;
6726 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6727 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6728 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6730 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6732 IWineD3DSurface_UnlockRect(pSourceSurface);
6733 IWineD3DSurface_UnlockRect(pDestinationSurface);
6734 TRACE("Unlocked src and dst\n");
6736 } else {
6738 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6739 hr = WINED3DERR_INVALIDCALL;
6742 } else {
6744 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6746 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6747 unsigned int i;
6749 /* Copy rect by rect */
6750 for (i = 0; i < cRects; ++i) {
6751 CONST RECT* r = &pSourceRectsArray[i];
6752 CONST POINT* p = &pDestPointsArray[i];
6753 int copyperline;
6754 int j;
6755 WINED3DLOCKED_RECT lrSrc;
6756 WINED3DLOCKED_RECT lrDst;
6757 RECT dest_rect;
6759 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6760 if (srcFormat == WINED3DFMT_DXT1) {
6761 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6762 } else {
6763 copyperline = ((r->right - r->left) * bytesPerPixel);
6766 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6767 dest_rect.left = p->x;
6768 dest_rect.top = p->y;
6769 dest_rect.right = p->x + (r->right - r->left);
6770 dest_rect.bottom= p->y + (r->bottom - r->top);
6771 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6772 TRACE("Locked src and dst\n");
6774 /* Find where to start */
6775 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6776 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6778 IWineD3DSurface_UnlockRect(pSourceSurface);
6779 IWineD3DSurface_UnlockRect(pDestinationSurface);
6780 TRACE("Unlocked src and dst\n");
6782 } else {
6783 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6784 hr = WINED3DERR_INVALIDCALL;
6788 return hr;
6791 /* Implementation details at http://developer.nvidia.com/attach/6494
6793 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6794 hmm.. no longer supported use
6795 OpenGL evaluators or tessellate surfaces within your application.
6798 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6799 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6801 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6802 FIXME("(%p) : Stub\n", This);
6803 return WINED3D_OK;
6807 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6808 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6810 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6811 FIXME("(%p) : Stub\n", This);
6812 return WINED3D_OK;
6815 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6817 TRACE("(%p) Handle(%d)\n", This, Handle);
6818 FIXME("(%p) : Stub\n", This);
6819 return WINED3D_OK;
6822 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6823 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6824 fill a surface with a block of color! */
6825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6826 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6827 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6828 IWineD3DSwapChainImpl *container = NULL;
6829 BOOL isRenderTarget = FALSE;
6830 unsigned int width, height;
6831 unsigned int top, left;
6832 unsigned int u, v;
6833 DWORD *data;
6834 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6836 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6837 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6838 return WINED3DERR_INVALIDCALL;
6841 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6842 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6843 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6844 /* TODO: make sure we set everything back to the way it was, and context management!
6845 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6846 vcheckGLcall("glIntegerv");
6847 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6848 vcheckGLcall("glIntegerv");
6850 TRACE("Color fill to render targets may cause some graphics issues\n");
6851 if (pSurface == container->frontBuffer) {
6852 glDrawBuffer(GL_FRONT);
6853 } else {
6854 glDrawBuffer(GL_BACK);
6856 } else {
6857 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6858 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6859 } else {
6860 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6862 if (container != NULL) {
6863 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6865 /* we can use GL_STENCIL_INDEX etc...*/
6866 return WINED3D_OK;
6868 if (container != NULL) {
6869 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6871 isRenderTarget = TRUE;
6873 /* TODO: drawing to GL_FRONT and GL_BACK */
6874 /* TODO: see if things can be speeded up by using the correct
6875 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6876 if (pRect == NULL) {
6877 top = 0;
6878 left = 0;
6879 width = surface->currentDesc.Width;
6880 height = surface->currentDesc.Height;
6881 } else {
6882 left = pRect->x1;
6883 top = pRect->y1;
6884 width = pRect->x2 - left;
6885 height = pRect->y2 - top;
6888 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6889 /* Create a 'line' of color color, in the correct format for the surface */
6890 for (u = 0 ; u < width ; u ++) {
6891 data[u] = color;
6894 ENTER_GL();
6895 if (isRenderTarget == FALSE) {
6896 glDescriptor *glDesc;
6897 IWineD3DSurface_PreLoad(pSurface);
6899 /* draw a block of the coloured line on the sufrace */
6900 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6901 for (v = 0 ; v< height;v++) {
6902 glTexSubImage2D(glDesc->target
6903 ,glDesc->level /* level */
6904 ,left
6905 ,top + v
6906 ,width
6907 ,1 /* height */
6908 ,GL_RGBA
6909 ,GL_UNSIGNED_BYTE
6910 ,data
6913 checkGLcall("glTexSubImage2D");
6914 /* clean up */
6915 glDisable(glDesc->target);
6916 } else {
6917 /** FIXME: Using GLClear may be faster **/
6918 glRasterPos2i(left, top);
6919 glPixelZoom((float)width ,(float)height);
6920 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6921 checkGLcall("glDrawPixels");
6923 HeapFree(GetProcessHeap(), 0, data);
6924 LEAVE_GL();
6925 return WINED3D_OK;
6929 /* rendertarget and deptth stencil functions */
6930 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6933 /* FIXME: Implelent RenderTargetIndex >0 */
6934 if(RenderTargetIndex > 0)
6935 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6937 *ppRenderTarget = This->renderTarget;
6938 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6939 /* Note inc ref on returned surface */
6940 if(*ppRenderTarget != NULL)
6941 IWineD3DSurface_AddRef(*ppRenderTarget);
6942 return WINED3D_OK;
6945 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6947 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6948 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6949 IWineD3DSwapChainImpl *Swapchain;
6950 HRESULT hr;
6952 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6954 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6955 if(hr != WINED3D_OK) {
6956 ERR("Can't get the swapchain\n");
6957 return hr;
6960 /* Make sure to release the swapchain */
6961 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6963 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6964 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6965 return WINED3DERR_INVALIDCALL;
6967 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6968 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6969 return WINED3DERR_INVALIDCALL;
6972 if(Swapchain->frontBuffer != Front) {
6973 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6975 if(Swapchain->frontBuffer)
6976 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6977 Swapchain->frontBuffer = Front;
6979 if(Swapchain->frontBuffer) {
6980 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6984 if(Back && !Swapchain->backBuffer) {
6985 /* We need memory for the back buffer array - only one back buffer this way */
6986 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6987 if(!Swapchain->backBuffer) {
6988 ERR("Out of memory\n");
6989 return E_OUTOFMEMORY;
6993 if(Swapchain->backBuffer[0] != Back) {
6994 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6995 ENTER_GL();
6996 if(!Swapchain->backBuffer[0]) {
6997 /* GL was told to draw to the front buffer at creation,
6998 * undo that
7000 glDrawBuffer(GL_BACK);
7001 checkGLcall("glDrawBuffer(GL_BACK)");
7002 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7003 Swapchain->presentParms.BackBufferCount = 1;
7004 } else if (!Back) {
7005 /* That makes problems - disable for now */
7006 /* glDrawBuffer(GL_FRONT); */
7007 checkGLcall("glDrawBuffer(GL_FRONT)");
7008 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7009 Swapchain->presentParms.BackBufferCount = 0;
7011 LEAVE_GL();
7013 if(Swapchain->backBuffer[0])
7014 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7015 Swapchain->backBuffer[0] = Back;
7017 if(Swapchain->backBuffer[0]) {
7018 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7019 } else {
7020 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7025 return WINED3D_OK;
7028 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7030 *ppZStencilSurface = This->depthStencilBuffer;
7031 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7033 if(*ppZStencilSurface != NULL) {
7034 /* Note inc ref on returned surface */
7035 IWineD3DSurface_AddRef(*ppZStencilSurface);
7037 return WINED3D_OK;
7040 /* internal static helper functions */
7041 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7042 IWineD3DSurface *RenderSurface);
7044 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7046 HRESULT hr = WINED3D_OK;
7047 WINED3DVIEWPORT viewport;
7049 TRACE("(%p) Swapping rendertarget\n",This);
7050 if (RenderTargetIndex > 0) {
7051 FIXME("(%p) Render targets other than the first are not supported\n",This);
7052 RenderTargetIndex = 0;
7055 /* MSDN says that null disables the render target
7056 but a device must always be associated with a render target
7057 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7059 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7060 for more details
7062 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7063 FIXME("Trying to set render target 0 to NULL\n");
7064 return WINED3DERR_INVALIDCALL;
7066 /* TODO: replace Impl* usage with interface usage */
7067 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7068 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);
7069 return WINED3DERR_INVALIDCALL;
7071 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7072 * builds, but I think wine counts as a 'debug' build for now.
7073 ******************************/
7074 /* If we are trying to set what we already have, don't bother */
7075 if (pRenderTarget == This->renderTarget) {
7076 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7077 } else {
7078 /* Otherwise, set the render target up */
7080 if (FALSE == This->sceneEnded) {
7081 IWineD3DDevice_EndScene(iface);
7083 TRACE("clearing renderer\n");
7084 /* IWineD3DDeviceImpl_CleanRender(iface); */
7085 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7086 depending on the renter target implementation being used.
7087 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7088 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7089 stencil buffer and incure an extra memory overhead */
7090 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7093 if (SUCCEEDED(hr)) {
7094 /* Finally, reset the viewport as the MSDN states. */
7095 /* TODO: Replace impl usage */
7096 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7097 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7098 viewport.X = 0;
7099 viewport.Y = 0;
7100 viewport.MaxZ = 1.0f;
7101 viewport.MinZ = 0.0f;
7102 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7103 } else {
7104 FIXME("Unknown error setting the render target\n");
7106 This->sceneEnded = FALSE;
7107 return hr;
7110 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7112 HRESULT hr = WINED3D_OK;
7113 IWineD3DSurface *tmp;
7115 TRACE("(%p) Swapping z-buffer\n",This);
7117 if (pNewZStencil == This->stencilBufferTarget) {
7118 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7119 } else {
7120 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7121 * depending on the renter target implementation being used.
7122 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7123 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7124 * stencil buffer and incure an extra memory overhead
7125 ******************************************************/
7128 tmp = This->stencilBufferTarget;
7129 This->stencilBufferTarget = pNewZStencil;
7130 /* should we be calling the parent or the wined3d surface? */
7131 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7132 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7133 hr = WINED3D_OK;
7134 /** TODO: glEnable/glDisable on depth/stencil depending on
7135 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7136 **********************************************************/
7139 return hr;
7143 #ifdef GL_VERSION_1_3
7144 /* Internal functions not in DirectX */
7145 /** TODO: move this off to the opengl context manager
7146 *(the swapchain doesn't need to know anything about offscreen rendering!)
7147 ****************************************************/
7149 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7153 TRACE("(%p), %p\n", This, swapchain);
7155 if (swapchain->win != swapchain->drawable) {
7156 /* Set everything back the way it ws */
7157 swapchain->render_ctx = swapchain->glCtx;
7158 swapchain->drawable = swapchain->win;
7160 return WINED3D_OK;
7163 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7164 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7166 int i;
7167 unsigned int width;
7168 unsigned int height;
7169 WINED3DFORMAT format;
7170 WINED3DSURFACE_DESC surfaceDesc;
7171 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7172 surfaceDesc.Width = &width;
7173 surfaceDesc.Height = &height;
7174 surfaceDesc.Format = &format;
7175 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7176 *context = NULL;
7177 /* I need a get width/height function (and should do something with the format) */
7178 for (i = 0; i < CONTEXT_CACHE; ++i) {
7179 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7180 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7181 the pSurface can be set to 0 allowing it to be reused from cache **/
7182 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7183 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7184 *context = &This->contextCache[i];
7185 break;
7187 if (This->contextCache[i].Width == 0) {
7188 This->contextCache[i].pSurface = pSurface;
7189 This->contextCache[i].Width = width;
7190 This->contextCache[i].Height = height;
7191 *context = &This->contextCache[i];
7192 break;
7195 if (i == CONTEXT_CACHE) {
7196 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7197 glContext *dropContext = 0;
7198 for (i = 0; i < CONTEXT_CACHE; i++) {
7199 if (This->contextCache[i].usedcount < minUsage) {
7200 dropContext = &This->contextCache[i];
7201 minUsage = This->contextCache[i].usedcount;
7204 /* clean up the context (this doesn't work for ATI at the moment */
7205 #if 0
7206 glXDestroyContext(swapchain->display, dropContext->context);
7207 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7208 #endif
7209 FIXME("Leak\n");
7210 dropContext->Width = 0;
7211 dropContext->pSurface = pSurface;
7212 *context = dropContext;
7213 } else {
7214 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7215 for (i = 0; i < CONTEXT_CACHE; i++) {
7216 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7220 if (*context != NULL)
7221 return WINED3D_OK;
7222 else
7223 return E_OUTOFMEMORY;
7225 #endif
7227 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7228 * the functionality needs splitting up so that we don't do more than we should do.
7229 * this only seems to impact performance a little.
7230 ******************************/
7231 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7232 IWineD3DSurface *RenderSurface) {
7233 HRESULT ret = WINED3DERR_INVALIDCALL;
7234 BOOL oldRecording;
7235 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7238 * Currently only active for GLX >= 1.3
7239 * for others versions we'll have to use GLXPixmaps
7241 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7242 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7243 * so only check OpenGL version
7244 * ..........................
7245 * I don't believe that it is a problem with NVidia headers,
7246 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7247 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7248 * ATI Note:
7249 * Your application will report GLX version 1.2 on glXQueryVersion.
7250 * However, it is safe to call the GLX 1.3 functions as described below.
7252 #if defined(GL_VERSION_1_3)
7254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7255 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7256 IWineD3DSurface *tmp;
7257 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7258 GLXFBConfig* cfgs = NULL;
7259 int nCfgs = 0;
7260 int attribs[256];
7261 int nAttribs = 0;
7262 IWineD3DSwapChain *currentSwapchain;
7263 IWineD3DSwapChainImpl *swapchain;
7264 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7265 * but switch them off if the StencilSurface is set to NULL
7266 ** *********************************************************/
7267 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7268 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7270 /**TODO:
7271 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7272 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7275 #define PUSH1(att) attribs[nAttribs++] = (att);
7276 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7278 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7280 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7281 IWineD3DSwapChainImpl *impSwapChain;
7282 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7283 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7284 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7287 ENTER_GL();
7289 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7290 PUSH2(GLX_X_RENDERABLE, TRUE);
7291 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7292 TRACE("calling makeglcfg\n");
7293 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7294 PUSH1(None);
7296 TRACE("calling chooseFGConfig\n");
7297 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7298 attribs, &nCfgs);
7300 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7301 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7302 why we failed and only show this message once! */
7303 MESSAGE("Failed to find exact match, finding alternative but you may suffer performance issues, try changing xfree's depth to match the requested depth\n"); /**/
7304 nAttribs = 0;
7305 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7306 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7307 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7308 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7309 TRACE("calling makeglcfg\n");
7310 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7311 PUSH1(None);
7312 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7313 attribs, &nCfgs);
7316 if (NULL != cfgs) {
7317 #ifdef EXTRA_TRACES
7318 int i;
7319 for (i = 0; i < nCfgs; ++i) {
7320 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7321 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7322 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7325 if (NULL != This->renderTarget) {
7326 glFlush();
7327 vcheckGLcall("glFlush");
7328 /** This is only useful if the old render target was a swapchain,
7329 * we need to supercede this with a function that displays
7330 * the current buffer on the screen. This is easy to do in glx1.3 but
7331 * we need to do copy-write pixels in glx 1.2.
7332 ************************************************/
7333 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7335 printf("Hit Enter to get next frame ...\n");
7336 getchar();
7338 #endif
7341 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7342 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7343 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7347 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7348 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7349 **********************************************************************/
7350 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7351 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7352 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7353 TRACE("making swapchain active\n");
7354 if (RenderSurface != This->renderTarget) {
7355 BOOL backbuf = FALSE;
7356 int i;
7358 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7359 if(RenderSurface == swapchain->backBuffer[i]) {
7360 backbuf = TRUE;
7361 break;
7365 if (backbuf) {
7366 } else {
7367 /* This could be flagged so that some operations work directly with the front buffer */
7368 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7370 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7371 == False) {
7372 TRACE("Error in setting current context: context %p drawable %ld !\n",
7373 impSwapChain->glCtx, impSwapChain->win);
7376 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7378 checkGLcall("glXMakeContextCurrent");
7380 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7382 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7384 /** ********************************************************************
7385 * This is a quickly hacked out implementation of offscreen textures.
7386 * It will work in most cases but there may be problems if the client
7387 * modifies the texture directly, or expects the contents of the rendertarget
7388 * to be persistent.
7390 * There are some real speed vs compatibility issues here:
7391 * we should really use a new context for every texture, but that eats ram.
7392 * we should also be restoring the texture to the pbuffer but that eats CPU
7393 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7394 * but if this means reusing the display backbuffer then we need to make sure that
7395 * states are correctly preserved.
7396 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7397 * and gain a good performance increase at the cost of compatibility.
7398 * I would suggest that, when this is the case, a user configurable flag be made
7399 * available, allowing the user to choose the best emulated experience for them.
7400 *********************************************************************/
7402 XVisualInfo *visinfo;
7403 glContext *newContext;
7405 /* Here were using a shared context model */
7406 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7407 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7410 /* If the context doesn't exist then create a new one */
7411 /* TODO: This should really be part of findGlContext */
7412 if (NULL == newContext->context) {
7414 TRACE("making new buffer\n");
7415 nAttribs = 0;
7416 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7417 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7418 PUSH1(None);
7420 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7422 /** ****************************************
7423 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7424 *they note:
7425 * In future releases, we may provide the calls glXCreateNewContext,
7426 * glXQueryDrawable and glXMakeContextCurrent.
7427 * so until then we have to use glXGetVisualFromFBConfig &co..
7428 ********************************************/
7431 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7432 if (!visinfo) {
7433 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7434 } else {
7435 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7436 XFree(visinfo);
7439 if (NULL == newContext || NULL == newContext->context) {
7440 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7441 } else {
7442 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7443 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7444 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7447 /* Clean up the old context */
7448 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7449 /* Set the current context of the swapchain to the new context */
7450 impSwapChain->drawable = newContext->drawable;
7451 impSwapChain->render_ctx = newContext->context;
7455 /* Disable recording, and apply the stateblock to the new context
7456 * FIXME: This is a bit of a hack, each context should know it's own state,
7457 * the directX current directX state should then be applied to the context */
7458 oldUpdateStateBlock = This->updateStateBlock;
7459 oldRecording= This->isRecordingState;
7460 This->isRecordingState = FALSE;
7461 This->updateStateBlock = This->stateBlock;
7462 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7464 /* clean up the current rendertargets swapchain (if it belonged to one) */
7465 if (currentSwapchain != NULL) {
7466 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7469 /* Were done with the opengl context management, setup the rendertargets */
7471 tmp = This->renderTarget;
7472 This->renderTarget = RenderSurface;
7473 IWineD3DSurface_AddRef(This->renderTarget);
7474 IWineD3DSurface_Release(tmp);
7477 DWORD value;
7479 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7480 /* Check that the container is not a swapchain member */
7482 IWineD3DSwapChain *tmpSwapChain;
7483 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7484 This->renderUpsideDown = TRUE;
7485 }else{
7486 This->renderUpsideDown = FALSE;
7487 IWineD3DSwapChain_Release(tmpSwapChain);
7489 /* Force updating the cull mode */
7490 TRACE("setting render state\n");
7491 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7492 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7494 /* Force updating projection matrix */
7495 This->last_was_rhw = FALSE;
7496 This->proj_valid = FALSE;
7499 /* Restore recording state */
7500 This->isRecordingState = oldRecording;
7501 This->updateStateBlock = oldUpdateStateBlock;
7503 ret = WINED3D_OK;
7505 if (cfgs != NULL) {
7506 XFree(cfgs);
7507 } else {
7508 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7509 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7512 #undef PUSH1
7513 #undef PUSH2
7514 if ( NULL != impSwapChain) {
7515 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7517 LEAVE_GL();
7519 #endif
7520 return ret;
7523 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7524 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7526 /* TODO: the use of Impl is deprecated. */
7527 /* some basic validation checks */
7528 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7530 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7532 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7533 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7534 return WINED3DERR_INVALIDCALL;
7536 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7537 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7538 return WINED3DERR_INVALIDCALL;
7540 /* TODO: make the cursor 'real' */
7542 This->xHotSpot = XHotSpot;
7543 This->yHotSpot = YHotSpot;
7545 return WINED3D_OK;
7548 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7550 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7552 This->xScreenSpace = XScreenSpace;
7553 This->yScreenSpace = YScreenSpace;
7555 return;
7559 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7561 TRACE("(%p) : visible(%d)\n", This, bShow);
7563 This->bCursorVisible = bShow;
7565 return WINED3D_OK;
7568 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7570 TRACE("(%p) : state (%lu)\n", This, This->state);
7571 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7572 switch (This->state) {
7573 case WINED3D_OK:
7574 return WINED3D_OK;
7575 case WINED3DERR_DEVICELOST:
7577 ResourceList *resourceList = This->resources;
7578 while (NULL != resourceList) {
7579 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7580 return WINED3DERR_DEVICENOTRESET;
7581 resourceList = resourceList->next;
7583 return WINED3DERR_DEVICELOST;
7585 case WINED3DERR_DRIVERINTERNALERROR:
7586 return WINED3DERR_DRIVERINTERNALERROR;
7589 /* Unknown state */
7590 return WINED3DERR_DRIVERINTERNALERROR;
7594 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7596 /** FIXME: Resource tracking needs to be done,
7597 * The closes we can do to this is set the priorities of all managed textures low
7598 * and then reset them.
7599 ***********************************************************/
7600 FIXME("(%p) : stub\n", This);
7601 return WINED3D_OK;
7604 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7606 /** FIXME: Resource trascking needs to be done.
7607 * in effect this pulls all non only default
7608 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7609 * and should clear down the context and set it up according to pPresentationParameters
7610 ***********************************************************/
7611 FIXME("(%p) : stub\n", This);
7612 return WINED3D_OK;
7615 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7617 /** FIXME: always true at the moment **/
7618 if(bEnableDialogs == FALSE) {
7619 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7621 return WINED3D_OK;
7625 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7627 TRACE("(%p) : pParameters %p\n", This, pParameters);
7629 *pParameters = This->createParms;
7630 return WINED3D_OK;
7633 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7634 IWineD3DSwapChain *swapchain;
7635 HRESULT hrc = WINED3D_OK;
7637 TRACE("Relaying to swapchain\n");
7639 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7640 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7641 IWineD3DSwapChain_Release(swapchain);
7643 return;
7646 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7647 IWineD3DSwapChain *swapchain;
7648 HRESULT hrc = WINED3D_OK;
7650 TRACE("Relaying to swapchain\n");
7652 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7653 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7654 IWineD3DSwapChain_Release(swapchain);
7656 return;
7660 /** ********************************************************
7661 * Notification functions
7662 ** ********************************************************/
7663 /** This function must be called in the release of a resource when ref == 0,
7664 * the contents of resource must still be correct,
7665 * any handels to other resource held by the caller must be closed
7666 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7667 *****************************************************/
7668 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7670 ResourceList* resourceList;
7672 TRACE("(%p) : resource %p\n", This, resource);
7673 #if 0
7674 EnterCriticalSection(&resourceStoreCriticalSection);
7675 #endif
7676 /* add a new texture to the frot of the linked list */
7677 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7678 resourceList->resource = resource;
7680 /* Get the old head */
7681 resourceList->next = This->resources;
7683 This->resources = resourceList;
7684 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7686 #if 0
7687 LeaveCriticalSection(&resourceStoreCriticalSection);
7688 #endif
7689 return;
7692 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7694 ResourceList* resourceList = NULL;
7695 ResourceList* previousResourceList = NULL;
7697 TRACE("(%p) : resource %p\n", This, resource);
7699 #if 0
7700 EnterCriticalSection(&resourceStoreCriticalSection);
7701 #endif
7702 resourceList = This->resources;
7704 while (resourceList != NULL) {
7705 if(resourceList->resource == resource) break;
7706 previousResourceList = resourceList;
7707 resourceList = resourceList->next;
7710 if (resourceList == NULL) {
7711 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7712 #if 0
7713 LeaveCriticalSection(&resourceStoreCriticalSection);
7714 #endif
7715 return;
7716 } else {
7717 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7719 /* make sure we don't leave a hole in the list */
7720 if (previousResourceList != NULL) {
7721 previousResourceList->next = resourceList->next;
7722 } else {
7723 This->resources = resourceList->next;
7726 #if 0
7727 LeaveCriticalSection(&resourceStoreCriticalSection);
7728 #endif
7729 return;
7733 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7735 int counter;
7737 TRACE("(%p) : resource %p\n", This, resource);
7738 switch(IWineD3DResource_GetType(resource)){
7739 case WINED3DRTYPE_SURFACE:
7740 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7741 break;
7742 case WINED3DRTYPE_TEXTURE:
7743 case WINED3DRTYPE_CUBETEXTURE:
7744 case WINED3DRTYPE_VOLUMETEXTURE:
7745 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7746 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7747 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7748 This->stateBlock->textures[counter] = NULL;
7750 if (This->updateStateBlock != This->stateBlock ){
7751 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7752 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7753 This->updateStateBlock->textures[counter] = NULL;
7757 break;
7758 case WINED3DRTYPE_VOLUME:
7759 /* TODO: nothing really? */
7760 break;
7761 case WINED3DRTYPE_VERTEXBUFFER:
7762 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7764 int streamNumber;
7765 TRACE("Cleaning up stream pointers\n");
7767 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7768 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7769 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7771 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7772 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7773 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7774 This->updateStateBlock->streamSource[streamNumber] = 0;
7775 /* Set changed flag? */
7778 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) */
7779 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7780 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7781 This->stateBlock->streamSource[streamNumber] = 0;
7784 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7785 else { /* This shouldn't happen */
7786 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7788 #endif
7792 break;
7793 case WINED3DRTYPE_INDEXBUFFER:
7794 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7795 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7796 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7797 This->updateStateBlock->pIndexData = NULL;
7800 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7801 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7802 This->stateBlock->pIndexData = NULL;
7806 break;
7807 default:
7808 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7809 break;
7813 /* Remove the resoruce from the resourceStore */
7814 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7816 TRACE("Resource released\n");
7820 /**********************************************************
7821 * IWineD3DDevice VTbl follows
7822 **********************************************************/
7824 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7826 /*** IUnknown methods ***/
7827 IWineD3DDeviceImpl_QueryInterface,
7828 IWineD3DDeviceImpl_AddRef,
7829 IWineD3DDeviceImpl_Release,
7830 /*** IWineD3DDevice methods ***/
7831 IWineD3DDeviceImpl_GetParent,
7832 /*** Creation methods**/
7833 IWineD3DDeviceImpl_CreateVertexBuffer,
7834 IWineD3DDeviceImpl_CreateIndexBuffer,
7835 IWineD3DDeviceImpl_CreateStateBlock,
7836 IWineD3DDeviceImpl_CreateSurface,
7837 IWineD3DDeviceImpl_CreateTexture,
7838 IWineD3DDeviceImpl_CreateVolumeTexture,
7839 IWineD3DDeviceImpl_CreateVolume,
7840 IWineD3DDeviceImpl_CreateCubeTexture,
7841 IWineD3DDeviceImpl_CreateQuery,
7842 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7843 IWineD3DDeviceImpl_CreateVertexDeclaration,
7844 IWineD3DDeviceImpl_CreateVertexShader,
7845 IWineD3DDeviceImpl_CreatePixelShader,
7846 IWineD3DDeviceImpl_CreatePalette,
7847 /*** Odd functions **/
7848 IWineD3DDeviceImpl_Init3D,
7849 IWineD3DDeviceImpl_Uninit3D,
7850 IWineD3DDeviceImpl_EnumDisplayModes,
7851 IWineD3DDeviceImpl_EvictManagedResources,
7852 IWineD3DDeviceImpl_GetAvailableTextureMem,
7853 IWineD3DDeviceImpl_GetBackBuffer,
7854 IWineD3DDeviceImpl_GetCreationParameters,
7855 IWineD3DDeviceImpl_GetDeviceCaps,
7856 IWineD3DDeviceImpl_GetDirect3D,
7857 IWineD3DDeviceImpl_GetDisplayMode,
7858 IWineD3DDeviceImpl_SetDisplayMode,
7859 IWineD3DDeviceImpl_GetHWND,
7860 IWineD3DDeviceImpl_SetHWND,
7861 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7862 IWineD3DDeviceImpl_GetRasterStatus,
7863 IWineD3DDeviceImpl_GetSwapChain,
7864 IWineD3DDeviceImpl_Reset,
7865 IWineD3DDeviceImpl_SetDialogBoxMode,
7866 IWineD3DDeviceImpl_SetCursorProperties,
7867 IWineD3DDeviceImpl_SetCursorPosition,
7868 IWineD3DDeviceImpl_ShowCursor,
7869 IWineD3DDeviceImpl_TestCooperativeLevel,
7870 /*** Getters and setters **/
7871 IWineD3DDeviceImpl_SetClipPlane,
7872 IWineD3DDeviceImpl_GetClipPlane,
7873 IWineD3DDeviceImpl_SetClipStatus,
7874 IWineD3DDeviceImpl_GetClipStatus,
7875 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7876 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7877 IWineD3DDeviceImpl_SetDepthStencilSurface,
7878 IWineD3DDeviceImpl_GetDepthStencilSurface,
7879 IWineD3DDeviceImpl_SetFVF,
7880 IWineD3DDeviceImpl_GetFVF,
7881 IWineD3DDeviceImpl_SetGammaRamp,
7882 IWineD3DDeviceImpl_GetGammaRamp,
7883 IWineD3DDeviceImpl_SetIndices,
7884 IWineD3DDeviceImpl_GetIndices,
7885 IWineD3DDeviceImpl_SetLight,
7886 IWineD3DDeviceImpl_GetLight,
7887 IWineD3DDeviceImpl_SetLightEnable,
7888 IWineD3DDeviceImpl_GetLightEnable,
7889 IWineD3DDeviceImpl_SetMaterial,
7890 IWineD3DDeviceImpl_GetMaterial,
7891 IWineD3DDeviceImpl_SetNPatchMode,
7892 IWineD3DDeviceImpl_GetNPatchMode,
7893 IWineD3DDeviceImpl_SetPaletteEntries,
7894 IWineD3DDeviceImpl_GetPaletteEntries,
7895 IWineD3DDeviceImpl_SetPixelShader,
7896 IWineD3DDeviceImpl_GetPixelShader,
7897 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7898 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7899 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7900 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7901 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7902 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7903 IWineD3DDeviceImpl_SetRenderState,
7904 IWineD3DDeviceImpl_GetRenderState,
7905 IWineD3DDeviceImpl_SetRenderTarget,
7906 IWineD3DDeviceImpl_GetRenderTarget,
7907 IWineD3DDeviceImpl_SetFrontBackBuffers,
7908 IWineD3DDeviceImpl_SetSamplerState,
7909 IWineD3DDeviceImpl_GetSamplerState,
7910 IWineD3DDeviceImpl_SetScissorRect,
7911 IWineD3DDeviceImpl_GetScissorRect,
7912 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7913 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7914 IWineD3DDeviceImpl_SetStreamSource,
7915 IWineD3DDeviceImpl_GetStreamSource,
7916 IWineD3DDeviceImpl_SetStreamSourceFreq,
7917 IWineD3DDeviceImpl_GetStreamSourceFreq,
7918 IWineD3DDeviceImpl_SetTexture,
7919 IWineD3DDeviceImpl_GetTexture,
7920 IWineD3DDeviceImpl_SetTextureStageState,
7921 IWineD3DDeviceImpl_GetTextureStageState,
7922 IWineD3DDeviceImpl_SetTransform,
7923 IWineD3DDeviceImpl_GetTransform,
7924 IWineD3DDeviceImpl_SetVertexDeclaration,
7925 IWineD3DDeviceImpl_GetVertexDeclaration,
7926 IWineD3DDeviceImpl_SetVertexShader,
7927 IWineD3DDeviceImpl_GetVertexShader,
7928 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7929 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7930 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7931 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7932 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7933 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7934 IWineD3DDeviceImpl_SetViewport,
7935 IWineD3DDeviceImpl_GetViewport,
7936 IWineD3DDeviceImpl_MultiplyTransform,
7937 IWineD3DDeviceImpl_ValidateDevice,
7938 IWineD3DDeviceImpl_ProcessVertices,
7939 /*** State block ***/
7940 IWineD3DDeviceImpl_BeginStateBlock,
7941 IWineD3DDeviceImpl_EndStateBlock,
7942 /*** Scene management ***/
7943 IWineD3DDeviceImpl_BeginScene,
7944 IWineD3DDeviceImpl_EndScene,
7945 IWineD3DDeviceImpl_Present,
7946 IWineD3DDeviceImpl_Clear,
7947 /*** Drawing ***/
7948 IWineD3DDeviceImpl_DrawPrimitive,
7949 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7950 IWineD3DDeviceImpl_DrawPrimitiveUP,
7951 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7952 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7953 IWineD3DDeviceImpl_DrawRectPatch,
7954 IWineD3DDeviceImpl_DrawTriPatch,
7955 IWineD3DDeviceImpl_DeletePatch,
7956 IWineD3DDeviceImpl_ColorFill,
7957 IWineD3DDeviceImpl_UpdateTexture,
7958 IWineD3DDeviceImpl_UpdateSurface,
7959 IWineD3DDeviceImpl_CopyRects,
7960 IWineD3DDeviceImpl_StretchRect,
7961 IWineD3DDeviceImpl_GetRenderTargetData,
7962 IWineD3DDeviceImpl_GetFrontBufferData,
7963 /*** Internal use IWineD3DDevice methods ***/
7964 IWineD3DDeviceImpl_SetupTextureStates,
7965 /*** object tracking ***/
7966 IWineD3DDeviceImpl_ResourceReleased
7970 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7971 WINED3DRS_ALPHABLENDENABLE ,
7972 WINED3DRS_ALPHAFUNC ,
7973 WINED3DRS_ALPHAREF ,
7974 WINED3DRS_ALPHATESTENABLE ,
7975 WINED3DRS_BLENDOP ,
7976 WINED3DRS_COLORWRITEENABLE ,
7977 WINED3DRS_DESTBLEND ,
7978 WINED3DRS_DITHERENABLE ,
7979 WINED3DRS_FILLMODE ,
7980 WINED3DRS_FOGDENSITY ,
7981 WINED3DRS_FOGEND ,
7982 WINED3DRS_FOGSTART ,
7983 WINED3DRS_LASTPIXEL ,
7984 WINED3DRS_SHADEMODE ,
7985 WINED3DRS_SRCBLEND ,
7986 WINED3DRS_STENCILENABLE ,
7987 WINED3DRS_STENCILFAIL ,
7988 WINED3DRS_STENCILFUNC ,
7989 WINED3DRS_STENCILMASK ,
7990 WINED3DRS_STENCILPASS ,
7991 WINED3DRS_STENCILREF ,
7992 WINED3DRS_STENCILWRITEMASK ,
7993 WINED3DRS_STENCILZFAIL ,
7994 WINED3DRS_TEXTUREFACTOR ,
7995 WINED3DRS_WRAP0 ,
7996 WINED3DRS_WRAP1 ,
7997 WINED3DRS_WRAP2 ,
7998 WINED3DRS_WRAP3 ,
7999 WINED3DRS_WRAP4 ,
8000 WINED3DRS_WRAP5 ,
8001 WINED3DRS_WRAP6 ,
8002 WINED3DRS_WRAP7 ,
8003 WINED3DRS_ZENABLE ,
8004 WINED3DRS_ZFUNC ,
8005 WINED3DRS_ZWRITEENABLE
8008 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8009 WINED3DTSS_ADDRESSW ,
8010 WINED3DTSS_ALPHAARG0 ,
8011 WINED3DTSS_ALPHAARG1 ,
8012 WINED3DTSS_ALPHAARG2 ,
8013 WINED3DTSS_ALPHAOP ,
8014 WINED3DTSS_BUMPENVLOFFSET ,
8015 WINED3DTSS_BUMPENVLSCALE ,
8016 WINED3DTSS_BUMPENVMAT00 ,
8017 WINED3DTSS_BUMPENVMAT01 ,
8018 WINED3DTSS_BUMPENVMAT10 ,
8019 WINED3DTSS_BUMPENVMAT11 ,
8020 WINED3DTSS_COLORARG0 ,
8021 WINED3DTSS_COLORARG1 ,
8022 WINED3DTSS_COLORARG2 ,
8023 WINED3DTSS_COLOROP ,
8024 WINED3DTSS_RESULTARG ,
8025 WINED3DTSS_TEXCOORDINDEX ,
8026 WINED3DTSS_TEXTURETRANSFORMFLAGS
8029 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8030 WINED3DSAMP_ADDRESSU ,
8031 WINED3DSAMP_ADDRESSV ,
8032 WINED3DSAMP_ADDRESSW ,
8033 WINED3DSAMP_BORDERCOLOR ,
8034 WINED3DSAMP_MAGFILTER ,
8035 WINED3DSAMP_MINFILTER ,
8036 WINED3DSAMP_MIPFILTER ,
8037 WINED3DSAMP_MIPMAPLODBIAS ,
8038 WINED3DSAMP_MAXMIPLEVEL ,
8039 WINED3DSAMP_MAXANISOTROPY ,
8040 WINED3DSAMP_SRGBTEXTURE ,
8041 WINED3DSAMP_ELEMENTINDEX
8044 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8045 WINED3DRS_AMBIENT ,
8046 WINED3DRS_AMBIENTMATERIALSOURCE ,
8047 WINED3DRS_CLIPPING ,
8048 WINED3DRS_CLIPPLANEENABLE ,
8049 WINED3DRS_COLORVERTEX ,
8050 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8051 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8052 WINED3DRS_FOGDENSITY ,
8053 WINED3DRS_FOGEND ,
8054 WINED3DRS_FOGSTART ,
8055 WINED3DRS_FOGTABLEMODE ,
8056 WINED3DRS_FOGVERTEXMODE ,
8057 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8058 WINED3DRS_LIGHTING ,
8059 WINED3DRS_LOCALVIEWER ,
8060 WINED3DRS_MULTISAMPLEANTIALIAS ,
8061 WINED3DRS_MULTISAMPLEMASK ,
8062 WINED3DRS_NORMALIZENORMALS ,
8063 WINED3DRS_PATCHEDGESTYLE ,
8064 WINED3DRS_POINTSCALE_A ,
8065 WINED3DRS_POINTSCALE_B ,
8066 WINED3DRS_POINTSCALE_C ,
8067 WINED3DRS_POINTSCALEENABLE ,
8068 WINED3DRS_POINTSIZE ,
8069 WINED3DRS_POINTSIZE_MAX ,
8070 WINED3DRS_POINTSIZE_MIN ,
8071 WINED3DRS_POINTSPRITEENABLE ,
8072 WINED3DRS_RANGEFOGENABLE ,
8073 WINED3DRS_SPECULARMATERIALSOURCE ,
8074 WINED3DRS_TWEENFACTOR ,
8075 WINED3DRS_VERTEXBLEND
8078 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8079 WINED3DTSS_TEXCOORDINDEX ,
8080 WINED3DTSS_TEXTURETRANSFORMFLAGS
8083 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8084 WINED3DSAMP_DMAPOFFSET