Assorted spelling fixes.
[wine.git] / dlls / wined3d / device.c
blob742951254b30e43281e4eb8af0117b09202997ef
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[WINED3DTS_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 Usage(%s)\n", object, debug_d3dusage(vboUsage));
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_DYNAMIC_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_DYNAMIC_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 being 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 %#lx\n", This, Width, Height, Levels, Usage);
1127 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1128 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1130 /* TODO: It should only be possible to create textures for formats
1131 that are reported as supported */
1132 if (WINED3DFMT_UNKNOWN >= Format) {
1133 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1134 return WINED3DERR_INVALIDCALL;
1137 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1138 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1139 object->width = Width;
1140 object->height = Height;
1142 /** Non-power2 support **/
1143 /* Find the nearest pow2 match */
1144 pow2Width = pow2Height = 1;
1145 while (pow2Width < Width) pow2Width <<= 1;
1146 while (pow2Height < Height) pow2Height <<= 1;
1148 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1149 /* Precalculated scaling for 'faked' non power of two texture coords */
1150 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1151 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1152 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1154 /* Calculate levels for mip mapping */
1155 if (Levels == 0) {
1156 TRACE("calculating levels %d\n", object->baseTexture.levels);
1157 object->baseTexture.levels++;
1158 tmpW = Width;
1159 tmpH = Height;
1160 while (tmpW > 1 || tmpH > 1) {
1161 tmpW = max(1, tmpW >> 1);
1162 tmpH = max(1, tmpH >> 1);
1163 object->baseTexture.levels++;
1165 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1168 /* Generate all the surfaces */
1169 tmpW = Width;
1170 tmpH = Height;
1171 for (i = 0; i < object->baseTexture.levels; i++)
1173 /* use the callback to create the texture surface */
1174 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1175 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1176 FIXME("Failed to create surface %p\n", object);
1177 /* clean up */
1178 object->surfaces[i] = NULL;
1179 IWineD3DTexture_Release((IWineD3DTexture *)object);
1181 *ppTexture = NULL;
1182 return hr;
1185 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1186 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1187 /* calculate the next mipmap level */
1188 tmpW = max(1, tmpW >> 1);
1189 tmpH = max(1, tmpH >> 1);
1192 TRACE("(%p) : Created texture %p\n", This, object);
1193 return WINED3D_OK;
1196 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1197 UINT Width, UINT Height, UINT Depth,
1198 UINT Levels, DWORD Usage,
1199 WINED3DFORMAT Format, WINED3DPOOL Pool,
1200 IWineD3DVolumeTexture **ppVolumeTexture,
1201 HANDLE *pSharedHandle, IUnknown *parent,
1202 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1205 IWineD3DVolumeTextureImpl *object;
1206 unsigned int i;
1207 UINT tmpW;
1208 UINT tmpH;
1209 UINT tmpD;
1211 /* TODO: It should only be possible to create textures for formats
1212 that are reported as supported */
1213 if (WINED3DFMT_UNKNOWN >= Format) {
1214 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1215 return WINED3DERR_INVALIDCALL;
1218 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1219 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1221 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1222 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1224 object->width = Width;
1225 object->height = Height;
1226 object->depth = Depth;
1228 /* Calculate levels for mip mapping */
1229 if (Levels == 0) {
1230 object->baseTexture.levels++;
1231 tmpW = Width;
1232 tmpH = Height;
1233 tmpD = Depth;
1234 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1235 tmpW = max(1, tmpW >> 1);
1236 tmpH = max(1, tmpH >> 1);
1237 tmpD = max(1, tmpD >> 1);
1238 object->baseTexture.levels++;
1240 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1243 /* Generate all the surfaces */
1244 tmpW = Width;
1245 tmpH = Height;
1246 tmpD = Depth;
1248 for (i = 0; i < object->baseTexture.levels; i++)
1250 /* Create the volume */
1251 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1252 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1254 /* Set it's container to this object */
1255 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1257 /* calcualte the next mipmap level */
1258 tmpW = max(1, tmpW >> 1);
1259 tmpH = max(1, tmpH >> 1);
1260 tmpD = max(1, tmpD >> 1);
1263 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1264 TRACE("(%p) : Created volume texture %p\n", This, object);
1265 return WINED3D_OK;
1268 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1269 UINT Width, UINT Height, UINT Depth,
1270 DWORD Usage,
1271 WINED3DFORMAT Format, WINED3DPOOL Pool,
1272 IWineD3DVolume** ppVolume,
1273 HANDLE* pSharedHandle, IUnknown *parent) {
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1276 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1277 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1279 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1281 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1282 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1284 object->currentDesc.Width = Width;
1285 object->currentDesc.Height = Height;
1286 object->currentDesc.Depth = Depth;
1287 object->bytesPerPixel = formatDesc->bpp;
1289 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1290 object->lockable = TRUE;
1291 object->locked = FALSE;
1292 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1293 object->dirty = TRUE;
1295 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1298 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1299 UINT Levels, DWORD Usage,
1300 WINED3DFORMAT Format, WINED3DPOOL Pool,
1301 IWineD3DCubeTexture **ppCubeTexture,
1302 HANDLE *pSharedHandle, IUnknown *parent,
1303 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1307 unsigned int i, j;
1308 UINT tmpW;
1309 HRESULT hr;
1310 unsigned int pow2EdgeLength = EdgeLength;
1312 /* TODO: It should only be possible to create textures for formats
1313 that are reported as supported */
1314 if (WINED3DFMT_UNKNOWN >= Format) {
1315 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1316 return WINED3DERR_INVALIDCALL;
1319 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1320 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1322 TRACE("(%p) Create Cube Texture\n", This);
1324 /** Non-power2 support **/
1326 /* Find the nearest pow2 match */
1327 pow2EdgeLength = 1;
1328 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1330 object->edgeLength = EdgeLength;
1331 /* TODO: support for native non-power 2 */
1332 /* Precalculated scaling for 'faked' non power of two texture coords */
1333 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1335 /* Calculate levels for mip mapping */
1336 if (Levels == 0) {
1337 object->baseTexture.levels++;
1338 tmpW = EdgeLength;
1339 while (tmpW > 1) {
1340 tmpW = max(1, tmpW >> 1);
1341 object->baseTexture.levels++;
1343 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1346 /* Generate all the surfaces */
1347 tmpW = EdgeLength;
1348 for (i = 0; i < object->baseTexture.levels; i++) {
1350 /* Create the 6 faces */
1351 for (j = 0; j < 6; j++) {
1353 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1354 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1356 if(hr!= WINED3D_OK) {
1357 /* clean up */
1358 int k;
1359 int l;
1360 for (l = 0; l < j; l++) {
1361 IWineD3DSurface_Release(object->surfaces[j][i]);
1363 for (k = 0; k < i; k++) {
1364 for (l = 0; l < 6; l++) {
1365 IWineD3DSurface_Release(object->surfaces[l][j]);
1369 FIXME("(%p) Failed to create surface\n",object);
1370 HeapFree(GetProcessHeap(),0,object);
1371 *ppCubeTexture = NULL;
1372 return hr;
1374 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1375 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1377 tmpW = max(1, tmpW >> 1);
1380 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1381 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1382 return WINED3D_OK;
1385 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1387 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1389 if (NULL == ppQuery) {
1390 /* Just a check to see if we support this type of query */
1391 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1392 switch(Type) {
1393 case WINED3DQUERYTYPE_OCCLUSION:
1394 TRACE("(%p) occlusion query\n", This);
1395 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1396 hr = WINED3D_OK;
1397 else
1398 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1399 break;
1400 case WINED3DQUERYTYPE_VCACHE:
1401 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1402 case WINED3DQUERYTYPE_VERTEXSTATS:
1403 case WINED3DQUERYTYPE_EVENT:
1404 case WINED3DQUERYTYPE_TIMESTAMP:
1405 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1406 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1407 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1408 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1409 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1410 case WINED3DQUERYTYPE_PIXELTIMINGS:
1411 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1412 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1413 default:
1414 FIXME("(%p) Unhandled query type %d\n", This, Type);
1416 return hr;
1419 D3DCREATEOBJECTINSTANCE(object, Query)
1420 object->type = Type;
1421 /* allocated the 'extended' data based on the type of query requested */
1422 switch(Type){
1423 case D3DQUERYTYPE_OCCLUSION:
1424 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1425 TRACE("(%p) Allocating data for an occlusion query\n", This);
1426 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1427 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1428 break;
1430 case D3DQUERYTYPE_VCACHE:
1431 case D3DQUERYTYPE_RESOURCEMANAGER:
1432 case D3DQUERYTYPE_VERTEXSTATS:
1433 case D3DQUERYTYPE_EVENT:
1434 case D3DQUERYTYPE_TIMESTAMP:
1435 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1436 case D3DQUERYTYPE_TIMESTAMPFREQ:
1437 case D3DQUERYTYPE_PIPELINETIMINGS:
1438 case D3DQUERYTYPE_INTERFACETIMINGS:
1439 case D3DQUERYTYPE_VERTEXTIMINGS:
1440 case D3DQUERYTYPE_PIXELTIMINGS:
1441 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1442 case D3DQUERYTYPE_CACHEUTILIZATION:
1443 default:
1444 object->extendedData = 0;
1445 FIXME("(%p) Unhandled query type %d\n",This , Type);
1447 TRACE("(%p) : Created Query %p\n", This, object);
1448 return WINED3D_OK;
1451 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1452 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1453 IUnknown* parent,
1454 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1455 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1458 HDC hDc;
1459 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1460 int num;
1461 XVisualInfo template;
1462 GLXContext oldContext;
1463 Drawable oldDrawable;
1464 HRESULT hr = WINED3D_OK;
1466 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1468 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1469 * does a device hold a reference to a swap chain giving them a lifetime of the device
1470 * or does the swap chain notify the device of its destruction.
1471 *******************************/
1473 /* Check the params */
1474 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1475 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1476 return WINED3DERR_INVALIDCALL;
1477 } else if (*pPresentationParameters->BackBufferCount > 1) {
1478 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");
1481 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1483 /*********************
1484 * Lookup the window Handle and the relating X window handle
1485 ********************/
1487 /* Setup hwnd we are using, plus which display this equates to */
1488 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1489 if (!object->win_handle) {
1490 object->win_handle = This->createParms.hFocusWindow;
1493 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1494 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1495 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1496 return WINED3DERR_NOTAVAILABLE;
1498 hDc = GetDC(object->win_handle);
1499 object->display = get_display(hDc);
1500 ReleaseDC(object->win_handle, hDc);
1501 TRACE("Using a display of %p %p\n", object->display, hDc);
1503 if (NULL == object->display || NULL == hDc) {
1504 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1505 return WINED3DERR_NOTAVAILABLE;
1508 if (object->win == 0) {
1509 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1510 return WINED3DERR_NOTAVAILABLE;
1513 * Create an opengl context for the display visual
1514 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1515 * use different properties after that point in time. FIXME: How to handle when requested format
1516 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1517 * it chooses is identical to the one already being used!
1518 **********************************/
1520 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1521 ENTER_GL();
1523 /* Create a new context for this swapchain */
1524 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1525 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1526 (or the best possible if none is requested) */
1527 TRACE("Found x visual ID : %ld\n", template.visualid);
1529 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1530 if (NULL == object->visInfo) {
1531 ERR("cannot really get XVisual\n");
1532 LEAVE_GL();
1533 return WINED3DERR_NOTAVAILABLE;
1534 } else {
1535 int n, value;
1536 /* Write out some debug info about the visual/s */
1537 TRACE("Using x visual ID : %ld\n", template.visualid);
1538 TRACE(" visual info: %p\n", object->visInfo);
1539 TRACE(" num items : %d\n", num);
1540 for (n = 0;n < num; n++) {
1541 TRACE("=====item=====: %d\n", n + 1);
1542 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1543 TRACE(" screen : %d\n", object->visInfo[n].screen);
1544 TRACE(" depth : %u\n", object->visInfo[n].depth);
1545 TRACE(" class : %d\n", object->visInfo[n].class);
1546 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1547 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1548 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1549 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1550 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1551 /* log some extra glx info */
1552 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1553 TRACE(" gl_aux_buffers : %d\n", value);
1554 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1555 TRACE(" gl_buffer_size : %d\n", value);
1556 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1557 TRACE(" gl_red_size : %d\n", value);
1558 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1559 TRACE(" gl_green_size : %d\n", value);
1560 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1561 TRACE(" gl_blue_size : %d\n", value);
1562 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1563 TRACE(" gl_alpha_size : %d\n", value);
1564 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1565 TRACE(" gl_depth_size : %d\n", value);
1566 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1567 TRACE(" gl_stencil_size : %d\n", value);
1569 /* Now choose a simila visual ID*/
1571 #ifdef USE_CONTEXT_MANAGER
1573 /** TODO: use a context mamager **/
1574 #endif
1577 IWineD3DSwapChain *implSwapChain;
1578 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1579 /* The first time around we create the context that is shared with all other swapchains and render targets */
1580 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1581 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1582 } else {
1584 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1585 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1586 /* and create a new context with the implicit swapchains context as the shared context */
1587 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1588 IWineD3DSwapChain_Release(implSwapChain);
1592 /* Cleanup */
1593 XFree(object->visInfo);
1594 object->visInfo = NULL;
1596 LEAVE_GL();
1598 if (!object->glCtx) {
1599 ERR("Failed to create GLX context\n");
1600 return WINED3DERR_NOTAVAILABLE;
1601 } else {
1602 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1603 object->win_handle, object->glCtx, object->win, object->visInfo);
1606 /*********************
1607 * Windowed / Fullscreen
1608 *******************/
1611 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1612 * so we should really check to see if there is a fullscreen swapchain already
1613 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1614 **************************************/
1616 if (!*(pPresentationParameters->Windowed)) {
1618 DEVMODEW devmode;
1619 HDC hdc;
1620 int bpp = 0;
1622 /* Get info on the current display setup */
1623 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1624 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1625 DeleteDC(hdc);
1627 /* Change the display settings */
1628 memset(&devmode, 0, sizeof(DEVMODEW));
1629 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1630 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1631 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1632 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1633 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1634 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1636 /* Make popup window */
1637 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1638 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1639 *(pPresentationParameters->BackBufferWidth),
1640 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1642 /* For GetDisplayMode */
1643 This->ddraw_width = devmode.dmPelsWidth;
1644 This->ddraw_height = devmode.dmPelsHeight;
1645 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1649 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1650 * then the corresponding dimension of the client area of the hDeviceWindow
1651 * (or the focus window, if hDeviceWindow is NULL) is taken.
1652 **********************/
1654 if (*(pPresentationParameters->Windowed) &&
1655 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1656 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1658 RECT Rect;
1659 GetClientRect(object->win_handle, &Rect);
1661 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1662 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1663 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1665 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1666 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1667 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1671 /*********************
1672 * finish off parameter initialization
1673 *******************/
1675 /* Put the correct figures in the presentation parameters */
1676 TRACE("Coppying accross presentaion paraneters\n");
1677 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1678 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1679 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1680 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1681 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1682 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1683 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1684 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1685 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1686 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1687 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1688 object->presentParms.Flags = *(pPresentationParameters->Flags);
1689 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1690 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1693 /*********************
1694 * Create the back, front and stencil buffers
1695 *******************/
1697 TRACE("calling rendertarget CB\n");
1698 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1699 object->presentParms.BackBufferWidth,
1700 object->presentParms.BackBufferHeight,
1701 object->presentParms.BackBufferFormat,
1702 object->presentParms.MultiSampleType,
1703 object->presentParms.MultiSampleQuality,
1704 TRUE /* Lockable */,
1705 &object->frontBuffer,
1706 NULL /* pShared (always null)*/);
1707 if (object->frontBuffer != NULL)
1708 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1710 if(object->presentParms.BackBufferCount > 0) {
1711 int i;
1713 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1714 if(!object->backBuffer) {
1715 ERR("Out of memory\n");
1717 if (object->frontBuffer) {
1718 IUnknown *bufferParent;
1719 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1720 IUnknown_Release(bufferParent); /* once for the get parent */
1721 if (IUnknown_Release(bufferParent) > 0) {
1722 FIXME("(%p) Something's still holding the front buffer\n",This);
1725 HeapFree(GetProcessHeap(), 0, object);
1726 return E_OUTOFMEMORY;
1729 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1730 TRACE("calling rendertarget CB\n");
1731 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1732 object->presentParms.BackBufferWidth,
1733 object->presentParms.BackBufferHeight,
1734 object->presentParms.BackBufferFormat,
1735 object->presentParms.MultiSampleType,
1736 object->presentParms.MultiSampleQuality,
1737 TRUE /* Lockable */,
1738 &object->backBuffer[i],
1739 NULL /* pShared (always null)*/);
1740 if(hr == WINED3D_OK && object->backBuffer[i]) {
1741 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1742 } else {
1743 break;
1746 } else {
1747 object->backBuffer = NULL;
1750 if (object->backBuffer != NULL) {
1751 ENTER_GL();
1752 glDrawBuffer(GL_BACK);
1753 checkGLcall("glDrawBuffer(GL_BACK)");
1754 LEAVE_GL();
1755 } else {
1756 /* Single buffering - draw to front buffer */
1757 ENTER_GL();
1758 glDrawBuffer(GL_FRONT);
1759 checkGLcall("glDrawBuffer(GL_FRONT)");
1760 LEAVE_GL();
1763 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1764 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1765 TRACE("Creating depth stencil buffer\n");
1766 if (This->depthStencilBuffer == NULL ) {
1767 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1768 object->presentParms.BackBufferWidth,
1769 object->presentParms.BackBufferHeight,
1770 object->presentParms.AutoDepthStencilFormat,
1771 object->presentParms.MultiSampleType,
1772 object->presentParms.MultiSampleQuality,
1773 FALSE /* FIXME: Discard */,
1774 &This->depthStencilBuffer,
1775 NULL /* pShared (always null)*/ );
1776 if (This->depthStencilBuffer != NULL)
1777 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1780 /** TODO: A check on width, height and multisample types
1781 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1782 ****************************/
1783 object->wantsDepthStencilBuffer = TRUE;
1784 } else {
1785 object->wantsDepthStencilBuffer = FALSE;
1788 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1791 /*********************
1792 * init the default renderTarget management
1793 *******************/
1794 object->drawable = object->win;
1795 object->render_ctx = object->glCtx;
1797 if (hr == WINED3D_OK) {
1798 /*********************
1799 * Setup some defaults and clear down the buffers
1800 *******************/
1801 ENTER_GL();
1802 /** save current context and drawable **/
1803 oldContext = glXGetCurrentContext();
1804 oldDrawable = glXGetCurrentDrawable();
1806 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1807 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1808 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1810 checkGLcall("glXMakeCurrent");
1812 TRACE("Setting up the screen\n");
1813 /* Clear the screen */
1814 glClearColor(1.0, 0.0, 0.0, 0.0);
1815 checkGLcall("glClearColor");
1816 glClearIndex(0);
1817 glClearDepth(1);
1818 glClearStencil(0xffff);
1820 checkGLcall("glClear");
1822 glColor3f(1.0, 1.0, 1.0);
1823 checkGLcall("glColor3f");
1825 glEnable(GL_LIGHTING);
1826 checkGLcall("glEnable");
1828 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1829 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1831 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1832 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1834 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1835 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1837 /* switch back to the original context (if there was one)*/
1838 if (This->swapchains) {
1839 /** TODO: restore the context and drawable **/
1840 glXMakeCurrent(object->display, oldDrawable, oldContext);
1843 LEAVE_GL();
1845 TRACE("Set swapchain to %p\n", object);
1846 } else { /* something went wrong so clean up */
1847 IUnknown* bufferParent;
1848 if (object->frontBuffer) {
1850 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1851 IUnknown_Release(bufferParent); /* once for the get parent */
1852 if (IUnknown_Release(bufferParent) > 0) {
1853 FIXME("(%p) Something's still holding the front buffer\n",This);
1856 if (object->backBuffer) {
1857 int i;
1858 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1859 if(object->backBuffer[i]) {
1860 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1861 IUnknown_Release(bufferParent); /* once for the get parent */
1862 if (IUnknown_Release(bufferParent) > 0) {
1863 FIXME("(%p) Something's still holding the back buffer\n",This);
1867 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1868 object->backBuffer = NULL;
1870 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1871 /* Clean up the context */
1872 /* check that we are the current context first (we shouldn't be though!) */
1873 if (object->glCtx != 0) {
1874 if(glXGetCurrentContext() == object->glCtx) {
1875 glXMakeCurrent(object->display, None, NULL);
1877 glXDestroyContext(object->display, object->glCtx);
1879 HeapFree(GetProcessHeap(), 0, object);
1883 return hr;
1886 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1887 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1889 TRACE("(%p)\n", This);
1891 return This->NumberOfSwapChains;
1894 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1896 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1898 if(iSwapChain < This->NumberOfSwapChains) {
1899 *pSwapChain = This->swapchains[iSwapChain];
1900 IWineD3DSwapChain_AddRef(*pSwapChain);
1901 TRACE("(%p) returning %p\n", This, *pSwapChain);
1902 return WINED3D_OK;
1903 } else {
1904 TRACE("Swapchain out of range\n");
1905 *pSwapChain = NULL;
1906 return WINED3DERR_INVALIDCALL;
1910 /*****
1911 * Vertex Declaration
1912 *****/
1913 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1915 IWineD3DVertexDeclarationImpl *object = NULL;
1916 HRESULT hr = WINED3D_OK;
1917 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1918 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1919 object->allFVF = 0;
1921 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1923 return hr;
1926 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1927 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1929 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1930 HRESULT hr = WINED3D_OK;
1931 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1932 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1934 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1936 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1937 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1938 if (pDeclaration != NULL) {
1939 IWineD3DVertexDeclaration *vertexDeclaration;
1940 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1941 if (WINED3D_OK == hr) {
1942 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1943 object->vertexDeclaration = vertexDeclaration;
1944 } else {
1945 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1946 IWineD3DVertexShader_Release(*ppVertexShader);
1947 return WINED3DERR_INVALIDCALL;
1951 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1953 if (WINED3D_OK != hr) {
1954 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1955 IWineD3DVertexShader_Release(*ppVertexShader);
1956 return WINED3DERR_INVALIDCALL;
1959 #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. */
1960 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1961 /* Foo */
1962 } else {
1963 /* Bar */
1966 #endif
1968 return WINED3D_OK;
1971 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1973 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1974 HRESULT hr = WINED3D_OK;
1976 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1977 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1978 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1979 if (WINED3D_OK == hr) {
1980 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1981 } else {
1982 WARN("(%p) : Failed to create pixel shader\n", This);
1985 return hr;
1988 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1990 IWineD3DPaletteImpl *object;
1991 HRESULT hr;
1992 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1994 /* Create the new object */
1995 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1996 if(!object) {
1997 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1998 return E_OUTOFMEMORY;
2001 object->lpVtbl = &IWineD3DPalette_Vtbl;
2002 object->ref = 1;
2003 object->Flags = Flags;
2004 object->parent = Parent;
2005 object->wineD3DDevice = This;
2006 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2008 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2010 if(!object->hpal) {
2011 HeapFree( GetProcessHeap(), 0, object);
2012 return E_OUTOFMEMORY;
2015 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2016 if(FAILED(hr)) {
2017 IWineD3DPalette_Release((IWineD3DPalette *) object);
2018 return hr;
2021 *Palette = (IWineD3DPalette *) object;
2023 return WINED3D_OK;
2026 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2028 IWineD3DSwapChainImpl *swapchain;
2030 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2031 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2033 /* TODO: Test if OpenGL is compiled in and loaded */
2035 /* Setup the implicit swapchain */
2036 TRACE("Creating implicit swapchain\n");
2037 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2038 WARN("Failed to create implicit swapchain\n");
2039 return WINED3DERR_INVALIDCALL;
2042 This->NumberOfSwapChains = 1;
2043 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2044 if(!This->swapchains) {
2045 ERR("Out of memory!\n");
2046 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2047 return E_OUTOFMEMORY;
2049 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2051 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2052 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2053 This->renderTarget = swapchain->backBuffer[0];
2055 else {
2056 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2057 This->renderTarget = swapchain->frontBuffer;
2059 IWineD3DSurface_AddRef(This->renderTarget);
2060 /* Depth Stencil support */
2061 This->stencilBufferTarget = This->depthStencilBuffer;
2062 if (NULL != This->stencilBufferTarget) {
2063 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2066 /* Set up some starting GL setup */
2067 ENTER_GL();
2069 * Initialize openGL extension related variables
2070 * with Default values
2073 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2074 /* Setup all the devices defaults */
2075 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2076 #if 0
2077 IWineD3DImpl_CheckGraphicsMemory();
2078 #endif
2079 LEAVE_GL();
2081 /* Initialize our list of GLSL programs */
2082 list_init(&This->glsl_shader_progs);
2084 { /* Set a default viewport */
2085 D3DVIEWPORT9 vp;
2086 vp.X = 0;
2087 vp.Y = 0;
2088 vp.Width = *(pPresentationParameters->BackBufferWidth);
2089 vp.Height = *(pPresentationParameters->BackBufferHeight);
2090 vp.MinZ = 0.0f;
2091 vp.MaxZ = 1.0f;
2092 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2095 /* Initialize the current view state */
2096 This->modelview_valid = 1;
2097 This->proj_valid = 0;
2098 This->view_ident = 1;
2099 This->last_was_rhw = 0;
2100 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2101 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2103 /* Clear the screen */
2104 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2106 This->d3d_initialized = TRUE;
2107 return WINED3D_OK;
2110 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2112 int sampler;
2113 IUnknown* stencilBufferParent;
2114 IUnknown* swapChainParent;
2115 uint i;
2116 TRACE("(%p)\n", This);
2118 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2120 /* Delete the mouse cursor texture */
2121 if(This->cursorTexture) {
2122 ENTER_GL();
2123 glDeleteTextures(1, &This->cursorTexture);
2124 LEAVE_GL();
2125 This->cursorTexture = 0;
2128 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2129 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2132 /* Release the buffers (with sanity checks)*/
2133 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2134 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2135 if(This->depthStencilBuffer != This->stencilBufferTarget)
2136 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2138 This->stencilBufferTarget = NULL;
2140 TRACE("Releasing the render target at %p\n", This->renderTarget);
2141 if(IWineD3DSurface_Release(This->renderTarget) >0){
2142 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2144 TRACE("Setting rendertarget to NULL\n");
2145 This->renderTarget = NULL;
2147 if (This->depthStencilBuffer) {
2148 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2149 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2150 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2151 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2153 This->depthStencilBuffer = NULL;
2156 for(i=0; i < This->NumberOfSwapChains; i++) {
2157 TRACE("Releasing the implicit swapchain %d\n", i);
2158 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2159 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2160 IUnknown_Release(swapChainParent); /* once for the get parent */
2161 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2162 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2166 HeapFree(GetProcessHeap(), 0, This->swapchains);
2167 This->swapchains = NULL;
2168 This->NumberOfSwapChains = 0;
2170 This->d3d_initialized = FALSE;
2171 return WINED3D_OK;
2174 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2177 DEVMODEW DevModeW;
2178 int i;
2179 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2181 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2183 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2184 /* Ignore some modes if a description was passed */
2185 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2186 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2187 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2189 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2191 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2192 return D3D_OK;
2195 return D3D_OK;
2198 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2199 DEVMODEW devmode;
2200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2201 LONG ret;
2202 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2204 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2206 /* Resize the screen even without a window:
2207 * The app could have unset it with SetCooperativeLevel, but not called
2208 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2209 * but we don't have any hwnd
2212 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2213 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2214 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2215 devmode.dmPelsWidth = pMode->Width;
2216 devmode.dmPelsHeight = pMode->Height;
2218 devmode.dmDisplayFrequency = pMode->RefreshRate;
2219 if (pMode->RefreshRate != 0) {
2220 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2223 /* Only change the mode if necessary */
2224 if( (This->ddraw_width == pMode->Width) &&
2225 (This->ddraw_height == pMode->Height) &&
2226 (This->ddraw_format == pMode->Format) &&
2227 (pMode->RefreshRate == 0) ) {
2228 return D3D_OK;
2231 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2232 if (ret != DISP_CHANGE_SUCCESSFUL) {
2233 if(devmode.dmDisplayFrequency != 0) {
2234 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2235 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2236 devmode.dmDisplayFrequency = 0;
2237 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2239 if(ret != DISP_CHANGE_SUCCESSFUL) {
2240 return DDERR_INVALIDMODE;
2244 /* Store the new values */
2245 This->ddraw_width = pMode->Width;
2246 This->ddraw_height = pMode->Height;
2247 This->ddraw_format = pMode->Format;
2249 /* Only do this with a window of course */
2250 if(This->ddraw_window)
2251 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2253 return WINED3D_OK;
2256 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2258 *ppD3D= This->wineD3D;
2259 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2260 IWineD3D_AddRef(*ppD3D);
2261 return WINED3D_OK;
2264 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2265 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2266 * Into the video ram as possible and seeing how many fit
2267 * you can also get the correct initial value from via X and ATI's driver
2268 *******************/
2269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2270 static BOOL showfixmes = TRUE;
2271 if (showfixmes) {
2272 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2273 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2274 showfixmes = FALSE;
2276 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2277 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2278 /* videomemory is simulated videomemory + AGP memory left */
2279 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2284 /*****
2285 * Get / Set FVF
2286 *****/
2287 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2289 HRESULT hr = WINED3D_OK;
2291 /* Update the current state block */
2292 This->updateStateBlock->fvf = fvf;
2293 This->updateStateBlock->changed.fvf = TRUE;
2294 This->updateStateBlock->set.fvf = TRUE;
2296 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2297 return hr;
2301 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2303 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2304 *pfvf = This->stateBlock->fvf;
2305 return WINED3D_OK;
2308 /*****
2309 * Get / Set Stream Source
2310 *****/
2311 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2313 IWineD3DVertexBuffer *oldSrc;
2315 /**TODO: instance and index data, see
2316 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2318 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2319 **************/
2321 /* D3d9 only, but shouldn't hurt d3d8 */
2322 UINT streamFlags;
2324 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2325 if (streamFlags) {
2326 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2327 FIXME("stream index data not supported\n");
2329 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2330 FIXME("stream instance data not supported\n");
2334 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2336 if (StreamNumber >= MAX_STREAMS) {
2337 WARN("Stream out of range %d\n", StreamNumber);
2338 return WINED3DERR_INVALIDCALL;
2341 oldSrc = This->stateBlock->streamSource[StreamNumber];
2342 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2344 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2345 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2346 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2347 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2348 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2349 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2351 /* Handle recording of state blocks */
2352 if (This->isRecordingState) {
2353 TRACE("Recording... not performing anything\n");
2354 return WINED3D_OK;
2357 /* Same stream object: no action */
2358 if (oldSrc == pStreamData)
2359 return WINED3D_OK;
2361 /* Need to do a getParent and pass the reffs up */
2362 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2363 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2364 so for now, just count internally */
2365 if (pStreamData != NULL) {
2366 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2367 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2368 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2370 vbImpl->stream = StreamNumber;
2371 vbImpl->Flags |= VBFLAG_STREAM;
2372 IWineD3DVertexBuffer_AddRef(pStreamData);
2374 if (oldSrc != NULL) {
2375 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2376 IWineD3DVertexBuffer_Release(oldSrc);
2379 return WINED3D_OK;
2382 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 UINT streamFlags;
2386 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2387 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2390 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2391 if (streamFlags) {
2392 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2393 FIXME("stream index data not supported\n");
2395 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2396 FIXME("stream instance data not supported\n");
2400 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2402 if (StreamNumber >= MAX_STREAMS) {
2403 WARN("Stream out of range %d\n", StreamNumber);
2404 return WINED3DERR_INVALIDCALL;
2406 *pStream = This->stateBlock->streamSource[StreamNumber];
2407 *pStride = This->stateBlock->streamStride[StreamNumber];
2408 if (pOffset) {
2409 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2412 if (*pStream == NULL) {
2413 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2414 return WINED3DERR_INVALIDCALL;
2417 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2418 return WINED3D_OK;
2421 /*Should be quite easy, just an extension of vertexdata
2422 ref...
2423 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2425 The divider is a bit odd though
2427 VertexOffset = StartVertex / Divider * StreamStride +
2428 VertexIndex / Divider * StreamStride + StreamOffset
2431 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2434 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2435 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2437 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2438 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2439 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2441 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2442 FIXME("Stream indexing not fully supported\n");
2445 return WINED3D_OK;
2448 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2451 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2452 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2454 TRACE("(%p) : returning %d\n", This, *Divider);
2456 return WINED3D_OK;
2459 /*****
2460 * Get / Set & Multiply Transform
2461 *****/
2462 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 /* Most of this routine, comments included copied from ddraw tree initially: */
2466 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2468 /* Handle recording of state blocks */
2469 if (This->isRecordingState) {
2470 TRACE("Recording... not performing anything\n");
2471 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2472 This->updateStateBlock->set.transform[d3dts] = TRUE;
2473 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2474 return WINED3D_OK;
2478 * If the new matrix is the same as the current one,
2479 * we cut off any further processing. this seems to be a reasonable
2480 * optimization because as was noticed, some apps (warcraft3 for example)
2481 * tend towards setting the same matrix repeatedly for some reason.
2483 * From here on we assume that the new matrix is different, wherever it matters.
2485 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2486 TRACE("The app is setting the same matrix over again\n");
2487 return WINED3D_OK;
2488 } else {
2489 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2493 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2494 where ViewMat = Camera space, WorldMat = world space.
2496 In OpenGL, camera and world space is combined into GL_MODELVIEW
2497 matrix. The Projection matrix stay projection matrix.
2500 /* Capture the times we can just ignore the change for now */
2501 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2502 This->modelview_valid = FALSE;
2503 return WINED3D_OK;
2505 } else if (d3dts == WINED3DTS_PROJECTION) {
2506 This->proj_valid = FALSE;
2507 return WINED3D_OK;
2509 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2510 /* Indexed Vertex Blending Matrices 256 -> 511 */
2511 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2512 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2513 return WINED3D_OK;
2516 /* Now we really are going to have to change a matrix */
2517 ENTER_GL();
2519 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2520 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2521 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2522 unsigned int k;
2524 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2525 * NOTE: We have to reset the positions even if the light/plane is not currently
2526 * enabled, since the call to enable it will not reset the position.
2527 * NOTE2: Apparently texture transforms do NOT need reapplying
2530 PLIGHTINFOEL *lightChain = NULL;
2531 This->modelview_valid = FALSE;
2532 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2534 glMatrixMode(GL_MODELVIEW);
2535 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2536 glPushMatrix();
2537 glLoadMatrixf((float *)lpmatrix);
2538 checkGLcall("glLoadMatrixf(...)");
2540 /* Reset lights */
2541 lightChain = This->stateBlock->lights;
2542 while (lightChain && lightChain->glIndex != -1) {
2543 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2544 checkGLcall("glLightfv posn");
2545 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2546 checkGLcall("glLightfv dirn");
2547 lightChain = lightChain->next;
2550 /* Reset Clipping Planes if clipping is enabled */
2551 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2552 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2553 checkGLcall("glClipPlane");
2555 glPopMatrix();
2557 } else { /* What was requested!?? */
2558 WARN("invalid matrix specified: %i\n", d3dts);
2561 /* Release lock, all done */
2562 LEAVE_GL();
2563 return WINED3D_OK;
2566 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2569 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2570 return WINED3D_OK;
2573 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2574 D3DMATRIX *mat = NULL;
2575 D3DMATRIX temp;
2577 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2578 * below means it will be recorded in a state block change, but it
2579 * works regardless where it is recorded.
2580 * If this is found to be wrong, change to StateBlock.
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2585 if (State < HIGHEST_TRANSFORMSTATE)
2587 mat = &This->updateStateBlock->transforms[State];
2588 } else {
2589 FIXME("Unhandled transform state!!\n");
2592 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2594 /* Apply change via set transform - will reapply to eg. lights this way */
2595 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2598 /*****
2599 * Get / Set Light
2600 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2601 *****/
2602 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2603 you can reference any indexes you want as long as that number max are enabled at any
2604 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2605 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2606 but when recording, just build a chain pretty much of commands to be replayed. */
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2609 float rho;
2610 PLIGHTINFOEL *object, *temp;
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2615 /* If recording state block, just add to end of lights chain */
2616 if (This->isRecordingState) {
2617 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2618 if (NULL == object) {
2619 return WINED3DERR_OUTOFVIDEOMEMORY;
2621 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2622 object->OriginalIndex = Index;
2623 object->glIndex = -1;
2624 object->changed = TRUE;
2626 /* Add to the END of the chain of lights changes to be replayed */
2627 if (This->updateStateBlock->lights == NULL) {
2628 This->updateStateBlock->lights = object;
2629 } else {
2630 temp = This->updateStateBlock->lights;
2631 while (temp->next != NULL) temp=temp->next;
2632 temp->next = object;
2634 TRACE("Recording... not performing anything more\n");
2635 return WINED3D_OK;
2638 /* Ok, not recording any longer so do real work */
2639 object = This->stateBlock->lights;
2640 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2642 /* If we didn't find it in the list of lights, time to add it */
2643 if (object == NULL) {
2644 PLIGHTINFOEL *insertAt,*prevPos;
2646 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2647 if (NULL == object) {
2648 return WINED3DERR_OUTOFVIDEOMEMORY;
2650 object->OriginalIndex = Index;
2651 object->glIndex = -1;
2653 /* Add it to the front of list with the idea that lights will be changed as needed
2654 BUT after any lights currently assigned GL indexes */
2655 insertAt = This->stateBlock->lights;
2656 prevPos = NULL;
2657 while (insertAt != NULL && insertAt->glIndex != -1) {
2658 prevPos = insertAt;
2659 insertAt = insertAt->next;
2662 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2663 This->stateBlock->lights = object;
2664 } else if (insertAt == NULL) { /* End of list */
2665 prevPos->next = object;
2666 object->prev = prevPos;
2667 } else { /* Middle of chain */
2668 if (prevPos == NULL) {
2669 This->stateBlock->lights = object;
2670 } else {
2671 prevPos->next = object;
2673 object->prev = prevPos;
2674 object->next = insertAt;
2675 insertAt->prev = object;
2679 /* Initialize the object */
2680 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,
2681 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2682 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2683 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2684 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2685 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2686 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2688 /* Save away the information */
2689 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2691 switch (pLight->Type) {
2692 case D3DLIGHT_POINT:
2693 /* Position */
2694 object->lightPosn[0] = pLight->Position.x;
2695 object->lightPosn[1] = pLight->Position.y;
2696 object->lightPosn[2] = pLight->Position.z;
2697 object->lightPosn[3] = 1.0f;
2698 object->cutoff = 180.0f;
2699 /* FIXME: Range */
2700 break;
2702 case D3DLIGHT_DIRECTIONAL:
2703 /* Direction */
2704 object->lightPosn[0] = -pLight->Direction.x;
2705 object->lightPosn[1] = -pLight->Direction.y;
2706 object->lightPosn[2] = -pLight->Direction.z;
2707 object->lightPosn[3] = 0.0;
2708 object->exponent = 0.0f;
2709 object->cutoff = 180.0f;
2710 break;
2712 case D3DLIGHT_SPOT:
2713 /* Position */
2714 object->lightPosn[0] = pLight->Position.x;
2715 object->lightPosn[1] = pLight->Position.y;
2716 object->lightPosn[2] = pLight->Position.z;
2717 object->lightPosn[3] = 1.0;
2719 /* Direction */
2720 object->lightDirn[0] = pLight->Direction.x;
2721 object->lightDirn[1] = pLight->Direction.y;
2722 object->lightDirn[2] = pLight->Direction.z;
2723 object->lightDirn[3] = 1.0;
2726 * opengl-ish and d3d-ish spot lights use too different models for the
2727 * light "intensity" as a function of the angle towards the main light direction,
2728 * so we only can approximate very roughly.
2729 * however spot lights are rather rarely used in games (if ever used at all).
2730 * furthermore if still used, probably nobody pays attention to such details.
2732 if (pLight->Falloff == 0) {
2733 rho = 6.28f;
2734 } else {
2735 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2737 if (rho < 0.0001) rho = 0.0001f;
2738 object->exponent = -0.3/log(cos(rho/2));
2739 object->cutoff = pLight->Phi*90/M_PI;
2741 /* FIXME: Range */
2742 break;
2744 default:
2745 FIXME("Unrecognized light type %d\n", pLight->Type);
2748 /* Update the live definitions if the light is currently assigned a glIndex */
2749 if (object->glIndex != -1) {
2750 setup_light(iface, object->glIndex, object);
2752 return WINED3D_OK;
2755 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2756 PLIGHTINFOEL *lightInfo = NULL;
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2760 /* Locate the light in the live lights */
2761 lightInfo = This->stateBlock->lights;
2762 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2764 if (lightInfo == NULL) {
2765 TRACE("Light information requested but light not defined\n");
2766 return WINED3DERR_INVALIDCALL;
2769 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2770 return WINED3D_OK;
2773 /*****
2774 * Get / Set Light Enable
2775 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2776 *****/
2777 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2778 PLIGHTINFOEL *lightInfo = NULL;
2779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2780 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2782 /* Tests show true = 128...not clear why */
2784 Enable = Enable? 128: 0;
2786 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2787 if (This->isRecordingState) {
2788 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2789 if (NULL == lightInfo) {
2790 return WINED3DERR_OUTOFVIDEOMEMORY;
2792 lightInfo->OriginalIndex = Index;
2793 lightInfo->glIndex = -1;
2794 lightInfo->enabledChanged = TRUE;
2795 lightInfo->lightEnabled = Enable;
2797 /* Add to the END of the chain of lights changes to be replayed */
2798 if (This->updateStateBlock->lights == NULL) {
2799 This->updateStateBlock->lights = lightInfo;
2800 } else {
2801 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2802 while (temp->next != NULL) temp=temp->next;
2803 temp->next = lightInfo;
2805 TRACE("Recording... not performing anything more\n");
2806 return WINED3D_OK;
2809 /* Not recording... So, locate the light in the live lights */
2810 lightInfo = This->stateBlock->lights;
2811 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2813 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2814 if (lightInfo == NULL) {
2816 TRACE("Light enabled requested but light not defined, so defining one!\n");
2817 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2819 /* Search for it again! Should be fairly quick as near head of list */
2820 lightInfo = This->stateBlock->lights;
2821 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2822 if (lightInfo == NULL) {
2823 FIXME("Adding default lights has failed dismally\n");
2824 return WINED3DERR_INVALIDCALL;
2828 /* OK, we now have a light... */
2829 if (Enable == FALSE) {
2831 /* If we are disabling it, check it was enabled, and
2832 still only do something if it has assigned a glIndex (which it should have!) */
2833 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2834 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2835 ENTER_GL();
2836 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2837 checkGLcall("glDisable GL_LIGHT0+Index");
2838 LEAVE_GL();
2839 } else {
2840 TRACE("Nothing to do as light was not enabled\n");
2842 lightInfo->lightEnabled = Enable;
2843 } else {
2845 /* We are enabling it. If it is enabled, it's really simple */
2846 if (lightInfo->lightEnabled) {
2847 /* nop */
2848 TRACE("Nothing to do as light was enabled\n");
2850 /* If it already has a glIndex, it's still simple */
2851 } else if (lightInfo->glIndex != -1) {
2852 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2853 lightInfo->lightEnabled = Enable;
2854 ENTER_GL();
2855 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2856 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2857 LEAVE_GL();
2859 /* Otherwise got to find space - lights are ordered gl indexes first */
2860 } else {
2861 PLIGHTINFOEL *bsf = NULL;
2862 PLIGHTINFOEL *pos = This->stateBlock->lights;
2863 PLIGHTINFOEL *prev = NULL;
2864 int Index= 0;
2865 int glIndex = -1;
2867 /* Try to minimize changes as much as possible */
2868 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2870 /* Try to remember which index can be replaced if necessary */
2871 if (bsf==NULL && pos->lightEnabled == FALSE) {
2872 /* Found a light we can replace, save as best replacement */
2873 bsf = pos;
2876 /* Step to next space */
2877 prev = pos;
2878 pos = pos->next;
2879 Index ++;
2882 /* If we have too many active lights, fail the call */
2883 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2884 FIXME("Program requests too many concurrent lights\n");
2885 return WINED3DERR_INVALIDCALL;
2887 /* If we have allocated all lights, but not all are enabled,
2888 reuse one which is not enabled */
2889 } else if (Index == This->maxConcurrentLights) {
2890 /* use bsf - Simply swap the new light and the BSF one */
2891 PLIGHTINFOEL *bsfNext = bsf->next;
2892 PLIGHTINFOEL *bsfPrev = bsf->prev;
2894 /* Sort out ends */
2895 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2896 if (bsf->prev != NULL) {
2897 bsf->prev->next = lightInfo;
2898 } else {
2899 This->stateBlock->lights = lightInfo;
2902 /* If not side by side, lots of chains to update */
2903 if (bsf->next != lightInfo) {
2904 lightInfo->prev->next = bsf;
2905 bsf->next->prev = lightInfo;
2906 bsf->next = lightInfo->next;
2907 bsf->prev = lightInfo->prev;
2908 lightInfo->next = bsfNext;
2909 lightInfo->prev = bsfPrev;
2911 } else {
2912 /* Simple swaps */
2913 bsf->prev = lightInfo;
2914 bsf->next = lightInfo->next;
2915 lightInfo->next = bsf;
2916 lightInfo->prev = bsfPrev;
2920 /* Update states */
2921 glIndex = bsf->glIndex;
2922 bsf->glIndex = -1;
2923 lightInfo->glIndex = glIndex;
2924 lightInfo->lightEnabled = Enable;
2926 /* Finally set up the light in gl itself */
2927 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2928 ENTER_GL();
2929 setup_light(iface, glIndex, lightInfo);
2930 glEnable(GL_LIGHT0 + glIndex);
2931 checkGLcall("glEnable GL_LIGHT0 new setup");
2932 LEAVE_GL();
2934 /* If we reached the end of the allocated lights, with space in the
2935 gl lights, setup a new light */
2936 } else if (pos->glIndex == -1) {
2938 /* We reached the end of the allocated gl lights, so already
2939 know the index of the next one! */
2940 glIndex = Index;
2941 lightInfo->glIndex = glIndex;
2942 lightInfo->lightEnabled = Enable;
2944 /* In an ideal world, it's already in the right place */
2945 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2946 /* No need to move it */
2947 } else {
2948 /* Remove this light from the list */
2949 lightInfo->prev->next = lightInfo->next;
2950 if (lightInfo->next != NULL) {
2951 lightInfo->next->prev = lightInfo->prev;
2954 /* Add in at appropriate place (inbetween prev and pos) */
2955 lightInfo->prev = prev;
2956 lightInfo->next = pos;
2957 if (prev == NULL) {
2958 This->stateBlock->lights = lightInfo;
2959 } else {
2960 prev->next = lightInfo;
2962 if (pos != NULL) {
2963 pos->prev = lightInfo;
2967 /* Finally set up the light in gl itself */
2968 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2969 ENTER_GL();
2970 setup_light(iface, glIndex, lightInfo);
2971 glEnable(GL_LIGHT0 + glIndex);
2972 checkGLcall("glEnable GL_LIGHT0 new setup");
2973 LEAVE_GL();
2978 return WINED3D_OK;
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2983 PLIGHTINFOEL *lightInfo = NULL;
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 TRACE("(%p) : for idx(%ld)\n", This, Index);
2987 /* Locate the light in the live lights */
2988 lightInfo = This->stateBlock->lights;
2989 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2991 if (lightInfo == NULL) {
2992 TRACE("Light enabled state requested but light not defined\n");
2993 return WINED3DERR_INVALIDCALL;
2995 *pEnable = lightInfo->lightEnabled;
2996 return WINED3D_OK;
2999 /*****
3000 * Get / Set Clip Planes
3001 *****/
3002 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3006 /* Validate Index */
3007 if (Index >= GL_LIMITS(clipplanes)) {
3008 TRACE("Application has requested clipplane this device doesn't support\n");
3009 return WINED3DERR_INVALIDCALL;
3012 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3013 This->updateStateBlock->set.clipplane[Index] = TRUE;
3014 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3015 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3016 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3017 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3019 /* Handle recording of state blocks */
3020 if (This->isRecordingState) {
3021 TRACE("Recording... not performing anything\n");
3022 return WINED3D_OK;
3025 /* Apply it */
3027 ENTER_GL();
3029 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3030 glMatrixMode(GL_MODELVIEW);
3031 glPushMatrix();
3032 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3034 TRACE("Clipplane [%f,%f,%f,%f]\n",
3035 This->updateStateBlock->clipplane[Index][0],
3036 This->updateStateBlock->clipplane[Index][1],
3037 This->updateStateBlock->clipplane[Index][2],
3038 This->updateStateBlock->clipplane[Index][3]);
3039 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3040 checkGLcall("glClipPlane");
3042 glPopMatrix();
3043 LEAVE_GL();
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 TRACE("(%p) : for idx %ld\n", This, Index);
3052 /* Validate Index */
3053 if (Index >= GL_LIMITS(clipplanes)) {
3054 TRACE("Application has requested clipplane this device doesn't support\n");
3055 return WINED3DERR_INVALIDCALL;
3058 pPlane[0] = This->stateBlock->clipplane[Index][0];
3059 pPlane[1] = This->stateBlock->clipplane[Index][1];
3060 pPlane[2] = This->stateBlock->clipplane[Index][2];
3061 pPlane[3] = This->stateBlock->clipplane[Index][3];
3062 return WINED3D_OK;
3065 /*****
3066 * Get / Set Clip Plane Status
3067 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3068 *****/
3069 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 FIXME("(%p) : stub\n", This);
3072 if (NULL == pClipStatus) {
3073 return WINED3DERR_INVALIDCALL;
3075 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3076 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3082 FIXME("(%p) : stub\n", This);
3083 if (NULL == pClipStatus) {
3084 return WINED3DERR_INVALIDCALL;
3086 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3087 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3088 return WINED3D_OK;
3091 /*****
3092 * Get / Set Material
3093 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3094 *****/
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 This->updateStateBlock->changed.material = TRUE;
3099 This->updateStateBlock->set.material = TRUE;
3100 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3102 /* Handle recording of state blocks */
3103 if (This->isRecordingState) {
3104 TRACE("Recording... not performing anything\n");
3105 return WINED3D_OK;
3108 ENTER_GL();
3109 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3110 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3111 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3112 pMaterial->Ambient.b, pMaterial->Ambient.a);
3113 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3114 pMaterial->Specular.b, pMaterial->Specular.a);
3115 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3116 pMaterial->Emissive.b, pMaterial->Emissive.a);
3117 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3119 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3120 checkGLcall("glMaterialfv(GL_AMBIENT)");
3121 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3122 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3124 /* Only change material color if specular is enabled, otherwise it is set to black */
3125 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3126 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3127 checkGLcall("glMaterialfv(GL_SPECULAR");
3128 } else {
3129 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3130 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3131 checkGLcall("glMaterialfv(GL_SPECULAR");
3133 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3134 checkGLcall("glMaterialfv(GL_EMISSION)");
3135 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3136 checkGLcall("glMaterialf(GL_SHININESS");
3138 LEAVE_GL();
3139 return WINED3D_OK;
3142 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3145 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3146 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3147 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3148 pMaterial->Ambient.b, pMaterial->Ambient.a);
3149 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3150 pMaterial->Specular.b, pMaterial->Specular.a);
3151 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3152 pMaterial->Emissive.b, pMaterial->Emissive.a);
3153 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3155 return WINED3D_OK;
3158 /*****
3159 * Get / Set Indices
3160 *****/
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3162 UINT BaseVertexIndex) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 IWineD3DIndexBuffer *oldIdxs;
3166 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3167 oldIdxs = This->updateStateBlock->pIndexData;
3169 This->updateStateBlock->changed.indices = TRUE;
3170 This->updateStateBlock->set.indices = TRUE;
3171 This->updateStateBlock->pIndexData = pIndexData;
3172 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3174 /* Handle recording of state blocks */
3175 if (This->isRecordingState) {
3176 TRACE("Recording... not performing anything\n");
3177 return WINED3D_OK;
3180 if (NULL != pIndexData) {
3181 IWineD3DIndexBuffer_AddRef(pIndexData);
3183 if (NULL != oldIdxs) {
3184 IWineD3DIndexBuffer_Release(oldIdxs);
3186 return WINED3D_OK;
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 *ppIndexData = This->stateBlock->pIndexData;
3194 /* up ref count on ppindexdata */
3195 if (*ppIndexData) {
3196 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3197 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3198 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3199 }else{
3200 TRACE("(%p) No index data set\n", This);
3202 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3204 return WINED3D_OK;
3207 /*****
3208 * Get / Set Viewports
3209 *****/
3210 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 TRACE("(%p)\n", This);
3214 This->updateStateBlock->changed.viewport = TRUE;
3215 This->updateStateBlock->set.viewport = TRUE;
3216 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3218 /* Handle recording of state blocks */
3219 if (This->isRecordingState) {
3220 TRACE("Recording... not performing anything\n");
3221 return WINED3D_OK;
3223 This->viewport_changed = TRUE;
3225 ENTER_GL();
3227 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3228 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3230 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3231 checkGLcall("glDepthRange");
3232 /* Note: GL requires lower left, DirectX supplies upper left */
3233 /* TODO: replace usage of renderTarget with context management */
3234 glViewport(pViewport->X,
3235 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3236 pViewport->Width, pViewport->Height);
3238 checkGLcall("glViewport");
3240 LEAVE_GL();
3242 return WINED3D_OK;
3246 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3248 TRACE("(%p)\n", This);
3249 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3250 return WINED3D_OK;
3253 static void renderstate_stencil_twosided(
3254 IWineD3DDeviceImpl *This,
3255 GLint face,
3256 GLint func,
3257 GLint ref,
3258 GLuint mask,
3259 GLint stencilFail,
3260 GLint depthFail,
3261 GLint stencilPass ) {
3262 #if 0 /* Don't use OpenGL 2.0 calls for now */
3263 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3264 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3265 checkGLcall("glStencilFuncSeparate(...)");
3266 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3267 checkGLcall("glStencilOpSeparate(...)");
3269 else
3270 #endif
3271 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3272 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3273 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3274 GL_EXTCALL(glActiveStencilFaceEXT(face));
3275 checkGLcall("glActiveStencilFaceEXT(...)");
3276 glStencilFunc(func, ref, mask);
3277 checkGLcall("glStencilFunc(...)");
3278 glStencilOp(stencilFail, depthFail, stencilPass);
3279 checkGLcall("glStencilOp(...)");
3280 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3281 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3282 checkGLcall("glStencilFuncSeparateATI(...)");
3283 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3284 checkGLcall("glStencilOpSeparateATI(...)");
3285 } else {
3286 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3290 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3291 DWORD onesided_enable = FALSE;
3292 DWORD twosided_enable = FALSE;
3293 GLint func = GL_ALWAYS;
3294 GLint func_ccw = GL_ALWAYS;
3295 GLint ref = 0;
3296 GLuint mask = 0;
3297 GLint stencilFail = GL_KEEP;
3298 GLint depthFail = GL_KEEP;
3299 GLint stencilPass = GL_KEEP;
3300 GLint stencilFail_ccw = GL_KEEP;
3301 GLint depthFail_ccw = GL_KEEP;
3302 GLint stencilPass_ccw = GL_KEEP;
3304 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3305 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3306 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3307 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3308 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3309 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3310 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3311 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3312 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3313 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3314 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3315 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3316 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3317 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3318 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3319 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3320 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3321 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3322 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3323 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3324 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3325 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3326 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3327 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3329 switch(State) {
3330 case WINED3DRS_STENCILENABLE :
3331 onesided_enable = Value;
3332 break;
3333 case WINED3DRS_TWOSIDEDSTENCILMODE :
3334 twosided_enable = Value;
3335 break;
3336 case WINED3DRS_STENCILFUNC :
3337 func = StencilFunc(Value);
3338 break;
3339 case WINED3DRS_CCW_STENCILFUNC :
3340 func_ccw = StencilFunc(Value);
3341 break;
3342 case WINED3DRS_STENCILREF :
3343 ref = Value;
3344 break;
3345 case WINED3DRS_STENCILMASK :
3346 mask = Value;
3347 break;
3348 case WINED3DRS_STENCILFAIL :
3349 stencilFail = StencilOp(Value);
3350 break;
3351 case WINED3DRS_STENCILZFAIL :
3352 depthFail = StencilOp(Value);
3353 break;
3354 case WINED3DRS_STENCILPASS :
3355 stencilPass = StencilOp(Value);
3356 break;
3357 case WINED3DRS_CCW_STENCILFAIL :
3358 stencilFail_ccw = StencilOp(Value);
3359 break;
3360 case WINED3DRS_CCW_STENCILZFAIL :
3361 depthFail_ccw = StencilOp(Value);
3362 break;
3363 case WINED3DRS_CCW_STENCILPASS :
3364 stencilPass_ccw = StencilOp(Value);
3365 break;
3366 default :
3367 ERR("This should not happen!");
3370 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3371 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3372 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3373 onesided_enable, twosided_enable, ref, mask,
3374 func, stencilFail, depthFail, stencilPass,
3375 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3377 if (twosided_enable) {
3378 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3379 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3380 } else {
3381 if (onesided_enable) {
3382 glEnable(GL_STENCIL_TEST);
3383 checkGLcall("glEnable GL_STENCIL_TEST");
3384 glStencilFunc(func, ref, mask);
3385 checkGLcall("glStencilFunc(...)");
3386 glStencilOp(stencilFail, depthFail, stencilPass);
3387 checkGLcall("glStencilOp(...)");
3388 } else {
3389 glDisable(GL_STENCIL_TEST);
3390 checkGLcall("glDisable GL_STENCIL_TEST");
3395 /*****
3396 * Get / Set Render States
3397 * TODO: Verify against dx9 definitions
3398 *****/
3399 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3402 DWORD OldValue = This->stateBlock->renderState[State];
3404 /* Simple way of referring to either a DWORD or a 4 byte float */
3405 union {
3406 DWORD d;
3407 float f;
3408 } tmpvalue;
3410 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3411 This->updateStateBlock->changed.renderState[State] = TRUE;
3412 This->updateStateBlock->set.renderState[State] = TRUE;
3413 This->updateStateBlock->renderState[State] = Value;
3415 /* Handle recording of state blocks */
3416 if (This->isRecordingState) {
3417 TRACE("Recording... not performing anything\n");
3418 return WINED3D_OK;
3421 ENTER_GL();
3423 switch (State) {
3424 case WINED3DRS_FILLMODE :
3425 switch ((D3DFILLMODE) Value) {
3426 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3427 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3428 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3429 default:
3430 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3432 checkGLcall("glPolygonMode (fillmode)");
3433 break;
3435 case WINED3DRS_LIGHTING :
3436 if (Value) {
3437 glEnable(GL_LIGHTING);
3438 checkGLcall("glEnable GL_LIGHTING");
3439 } else {
3440 glDisable(GL_LIGHTING);
3441 checkGLcall("glDisable GL_LIGHTING");
3443 break;
3445 case WINED3DRS_ZENABLE :
3446 switch ((D3DZBUFFERTYPE) Value) {
3447 case D3DZB_FALSE:
3448 glDisable(GL_DEPTH_TEST);
3449 checkGLcall("glDisable GL_DEPTH_TEST");
3450 break;
3451 case D3DZB_TRUE:
3452 glEnable(GL_DEPTH_TEST);
3453 checkGLcall("glEnable GL_DEPTH_TEST");
3454 break;
3455 case D3DZB_USEW:
3456 glEnable(GL_DEPTH_TEST);
3457 checkGLcall("glEnable GL_DEPTH_TEST");
3458 FIXME("W buffer is not well handled\n");
3459 break;
3460 default:
3461 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3463 break;
3465 case WINED3DRS_CULLMODE :
3467 /* If we are culling "back faces with clockwise vertices" then
3468 set front faces to be counter clockwise and enable culling
3469 of back faces */
3470 switch ((D3DCULL) Value) {
3471 case D3DCULL_NONE:
3472 glDisable(GL_CULL_FACE);
3473 checkGLcall("glDisable GL_CULL_FACE");
3474 break;
3475 case D3DCULL_CW:
3476 glEnable(GL_CULL_FACE);
3477 checkGLcall("glEnable GL_CULL_FACE");
3478 if (This->renderUpsideDown) {
3479 glFrontFace(GL_CW);
3480 checkGLcall("glFrontFace GL_CW");
3481 } else {
3482 glFrontFace(GL_CCW);
3483 checkGLcall("glFrontFace GL_CCW");
3485 glCullFace(GL_BACK);
3486 break;
3487 case D3DCULL_CCW:
3488 glEnable(GL_CULL_FACE);
3489 checkGLcall("glEnable GL_CULL_FACE");
3490 if (This->renderUpsideDown) {
3491 glFrontFace(GL_CCW);
3492 checkGLcall("glFrontFace GL_CCW");
3493 } else {
3494 glFrontFace(GL_CW);
3495 checkGLcall("glFrontFace GL_CW");
3497 glCullFace(GL_BACK);
3498 break;
3499 default:
3500 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3502 break;
3504 case WINED3DRS_SHADEMODE :
3505 switch ((D3DSHADEMODE) Value) {
3506 case D3DSHADE_FLAT:
3507 glShadeModel(GL_FLAT);
3508 checkGLcall("glShadeModel");
3509 break;
3510 case D3DSHADE_GOURAUD:
3511 glShadeModel(GL_SMOOTH);
3512 checkGLcall("glShadeModel");
3513 break;
3514 case D3DSHADE_PHONG:
3515 FIXME("D3DSHADE_PHONG isn't supported\n");
3516 break;
3517 default:
3518 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3520 break;
3522 case WINED3DRS_DITHERENABLE :
3523 if (Value) {
3524 glEnable(GL_DITHER);
3525 checkGLcall("glEnable GL_DITHER");
3526 } else {
3527 glDisable(GL_DITHER);
3528 checkGLcall("glDisable GL_DITHER");
3530 break;
3532 case WINED3DRS_ZWRITEENABLE :
3533 if (Value) {
3534 glDepthMask(1);
3535 checkGLcall("glDepthMask");
3536 } else {
3537 glDepthMask(0);
3538 checkGLcall("glDepthMask");
3540 break;
3542 case WINED3DRS_ZFUNC :
3544 int glParm = GL_LESS;
3546 switch ((D3DCMPFUNC) Value) {
3547 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3548 case D3DCMP_LESS: glParm=GL_LESS; break;
3549 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3550 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3551 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3552 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3553 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3554 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3555 default:
3556 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3558 glDepthFunc(glParm);
3559 checkGLcall("glDepthFunc");
3561 break;
3563 case WINED3DRS_AMBIENT :
3565 float col[4];
3566 D3DCOLORTOGLFLOAT4(Value, col);
3567 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3568 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3569 checkGLcall("glLightModel for MODEL_AMBIENT");
3572 break;
3574 case WINED3DRS_ALPHABLENDENABLE :
3575 if (Value) {
3576 glEnable(GL_BLEND);
3577 checkGLcall("glEnable GL_BLEND");
3578 } else {
3579 glDisable(GL_BLEND);
3580 checkGLcall("glDisable GL_BLEND");
3582 break;
3584 case WINED3DRS_SRCBLEND :
3585 case WINED3DRS_DESTBLEND :
3587 int newVal = GL_ZERO;
3588 switch (Value) {
3589 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3590 case D3DBLEND_ONE : newVal = GL_ONE; break;
3591 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3592 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3593 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3594 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3595 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3596 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3597 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3598 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3599 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3601 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3602 This->srcBlend = newVal;
3603 This->dstBlend = newVal;
3604 break;
3606 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3607 This->srcBlend = newVal;
3608 This->dstBlend = newVal;
3609 break;
3610 default:
3611 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3614 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3615 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3616 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3617 glBlendFunc(This->srcBlend, This->dstBlend);
3619 checkGLcall("glBlendFunc");
3621 break;
3623 case WINED3DRS_ALPHATESTENABLE :
3624 case WINED3DRS_ALPHAFUNC :
3625 case WINED3DRS_ALPHAREF :
3626 case WINED3DRS_COLORKEYENABLE :
3628 int glParm = 0.0;
3629 float ref = GL_LESS;
3630 BOOL enable_ckey = FALSE;
3632 IWineD3DSurfaceImpl *surf;
3634 /* Find out if the texture on the first stage has a ckey set */
3635 if(This->stateBlock->textures[0]) {
3636 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3637 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3640 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3641 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3642 glEnable(GL_ALPHA_TEST);
3643 checkGLcall("glEnable GL_ALPHA_TEST");
3644 } else {
3645 glDisable(GL_ALPHA_TEST);
3646 checkGLcall("glDisable GL_ALPHA_TEST");
3647 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3648 * enable call
3650 break;
3653 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3654 glParm = GL_NOTEQUAL;
3655 ref = 0.0;
3656 } else {
3657 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3659 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3660 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3661 case D3DCMP_LESS: glParm = GL_LESS; break;
3662 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3663 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3664 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3665 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3666 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3667 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3668 default:
3669 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3672 This->alphafunc = glParm;
3673 glAlphaFunc(glParm, ref);
3674 checkGLcall("glAlphaFunc");
3676 break;
3678 case WINED3DRS_CLIPPLANEENABLE :
3679 case WINED3DRS_CLIPPING :
3681 /* Ensure we only do the changed clip planes */
3682 DWORD enable = 0xFFFFFFFF;
3683 DWORD disable = 0x00000000;
3685 /* If enabling / disabling all */
3686 if (State == WINED3DRS_CLIPPING) {
3687 if (Value) {
3688 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3689 disable = 0x00;
3690 } else {
3691 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3692 enable = 0x00;
3694 } else {
3695 enable = Value & ~OldValue;
3696 disable = ~Value & OldValue;
3699 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3700 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3701 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3702 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3703 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3704 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3706 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3707 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3708 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3709 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3710 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3711 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3713 /** update clipping status */
3714 if (enable) {
3715 This->stateBlock->clip_status.ClipUnion = 0;
3716 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3717 } else {
3718 This->stateBlock->clip_status.ClipUnion = 0;
3719 This->stateBlock->clip_status.ClipIntersection = 0;
3722 break;
3724 case WINED3DRS_BLENDOP :
3726 int glParm = GL_FUNC_ADD;
3728 switch ((D3DBLENDOP) Value) {
3729 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3730 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3731 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3732 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3733 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3734 default:
3735 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3738 if(GL_SUPPORT(ARB_IMAGING)) {
3739 TRACE("glBlendEquation(%x)\n", glParm);
3740 GL_EXTCALL(glBlendEquation(glParm));
3741 checkGLcall("glBlendEquation");
3742 } else {
3743 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3746 break;
3748 case WINED3DRS_TEXTUREFACTOR :
3750 unsigned int i;
3752 /* Note the texture color applies to all textures whereas
3753 GL_TEXTURE_ENV_COLOR applies to active only */
3754 float col[4];
3755 D3DCOLORTOGLFLOAT4(Value, col);
3756 /* Set the default alpha blend color */
3757 if (GL_SUPPORT(ARB_IMAGING)) {
3758 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3759 checkGLcall("glBlendColor");
3760 } else {
3761 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3764 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3765 /* And now the default texture color as well */
3766 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3767 /* Note the D3DRS value applies to all textures, but GL has one
3768 per texture, so apply it now ready to be used! */
3769 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3770 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3771 checkGLcall("glActiveTextureARB");
3772 } else if (i>0) {
3773 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3776 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3777 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3781 break;
3783 case WINED3DRS_SPECULARENABLE :
3785 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3786 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3787 specular color. This is wrong:
3788 Separate specular color means the specular colour is maintained separately, whereas
3789 single color means it is merged in. However in both cases they are being used to
3790 some extent.
3791 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3792 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3793 running 1.4 yet!
3796 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3797 * Instead, we need to setup the FinalCombiner properly.
3799 * The default setup for the FinalCombiner is:
3801 * <variable> <input> <mapping> <usage>
3802 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3803 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3804 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3805 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3806 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3807 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3808 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3810 * That's pretty much fine as it is, except for variable B, which needs to take
3811 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3812 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3815 if (Value) {
3816 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3817 checkGLcall("glMaterialfv");
3818 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3819 glEnable(GL_COLOR_SUM_EXT);
3820 } else {
3821 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3823 checkGLcall("glEnable(GL_COLOR_SUM)");
3825 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3826 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3827 checkGLcall("glFinalCombinerInputNV()");
3829 } else {
3830 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3832 /* for the case of enabled lighting: */
3833 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3834 checkGLcall("glMaterialfv");
3836 /* for the case of disabled lighting: */
3837 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3838 glDisable(GL_COLOR_SUM_EXT);
3839 } else {
3840 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3842 checkGLcall("glDisable(GL_COLOR_SUM)");
3844 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3845 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3846 checkGLcall("glFinalCombinerInputNV()");
3850 break;
3852 case WINED3DRS_STENCILENABLE :
3853 case WINED3DRS_TWOSIDEDSTENCILMODE :
3854 case WINED3DRS_STENCILFUNC :
3855 case WINED3DRS_CCW_STENCILFUNC :
3856 case WINED3DRS_STENCILREF :
3857 case WINED3DRS_STENCILMASK :
3858 case WINED3DRS_STENCILFAIL :
3859 case WINED3DRS_STENCILZFAIL :
3860 case WINED3DRS_STENCILPASS :
3861 case WINED3DRS_CCW_STENCILFAIL :
3862 case WINED3DRS_CCW_STENCILZFAIL :
3863 case WINED3DRS_CCW_STENCILPASS :
3864 renderstate_stencil(This, State, Value);
3865 break;
3866 case WINED3DRS_STENCILWRITEMASK :
3868 glStencilMask(Value);
3869 TRACE("glStencilMask(%lu)\n", Value);
3870 checkGLcall("glStencilMask");
3872 break;
3874 case WINED3DRS_FOGENABLE :
3876 if (Value) {
3877 glEnable(GL_FOG);
3878 checkGLcall("glEnable GL_FOG");
3879 } else {
3880 glDisable(GL_FOG);
3881 checkGLcall("glDisable GL_FOG");
3884 break;
3886 case WINED3DRS_RANGEFOGENABLE :
3888 if (Value) {
3889 TRACE("Enabled RANGEFOG");
3890 } else {
3891 TRACE("Disabled RANGEFOG");
3894 break;
3896 case WINED3DRS_FOGCOLOR :
3898 float col[4];
3899 D3DCOLORTOGLFLOAT4(Value, col);
3900 /* Set the default alpha blend color */
3901 glFogfv(GL_FOG_COLOR, &col[0]);
3902 checkGLcall("glFog GL_FOG_COLOR");
3904 break;
3906 case WINED3DRS_FOGTABLEMODE :
3907 case WINED3DRS_FOGVERTEXMODE :
3909 /* 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." */
3910 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3911 glHint(GL_FOG_HINT, GL_FASTEST);
3912 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3913 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3914 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3915 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3917 case D3DFOG_EXP: {
3918 if(!This->last_was_rhw) {
3919 glFogi(GL_FOG_MODE, GL_EXP);
3920 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
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_EXP2: {
3931 if(!This->last_was_rhw) {
3932 glFogi(GL_FOG_MODE, GL_EXP2);
3933 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
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_LINEAR: {
3944 if(!This->last_was_rhw) {
3945 glFogi(GL_FOG_MODE, GL_LINEAR);
3946 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3947 if(GL_SUPPORT(EXT_FOG_COORD)) {
3948 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3949 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3950 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3951 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3953 break;
3956 case D3DFOG_NONE: {
3957 /* Both are none? According to msdn the alpha channel of the specular
3958 * color contains a fog factor. Set it in drawStridedSlow.
3959 * Same happens with Vertexfog on transformed vertices
3961 if(GL_SUPPORT(EXT_FOG_COORD)) {
3962 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3963 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3964 glFogi(GL_FOG_MODE, GL_LINEAR);
3965 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3966 glFogf(GL_FOG_START, (float) 0xff);
3967 checkGLcall("glFogfv GL_FOG_START");
3968 glFogf(GL_FOG_END, 0.0);
3969 checkGLcall("glFogfv GL_FOG_END");
3970 } else {
3971 /* Disable GL fog, handle this in software in drawStridedSlow */
3972 glDisable(GL_FOG);
3973 checkGLcall("glDisable(GL_FOG)");
3975 break;
3977 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3979 } else {
3980 glHint(GL_FOG_HINT, GL_NICEST);
3981 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3982 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3983 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3984 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3985 if(GL_SUPPORT(EXT_FOG_COORD)) {
3986 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3987 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3988 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3989 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3991 break;
3992 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3993 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3994 if(GL_SUPPORT(EXT_FOG_COORD)) {
3995 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3996 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3997 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3998 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4000 break;
4001 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
4002 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4003 if(GL_SUPPORT(EXT_FOG_COORD)) {
4004 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4005 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4006 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4007 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4009 break;
4010 case D3DFOG_NONE: /* Won't happen */
4011 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4014 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4015 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4018 break;
4020 case WINED3DRS_FOGSTART :
4022 tmpvalue.d = Value;
4023 glFogfv(GL_FOG_START, &tmpvalue.f);
4024 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4025 TRACE("Fog Start == %f\n", tmpvalue.f);
4027 break;
4029 case WINED3DRS_FOGEND :
4031 tmpvalue.d = Value;
4032 glFogfv(GL_FOG_END, &tmpvalue.f);
4033 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4034 TRACE("Fog End == %f\n", tmpvalue.f);
4036 break;
4038 case WINED3DRS_FOGDENSITY :
4040 tmpvalue.d = Value;
4041 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4042 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4044 break;
4046 case WINED3DRS_VERTEXBLEND :
4048 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4049 TRACE("Vertex Blending state to %ld\n", Value);
4051 break;
4053 case WINED3DRS_TWEENFACTOR :
4055 tmpvalue.d = Value;
4056 This->updateStateBlock->tween_factor = tmpvalue.f;
4057 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4059 break;
4061 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4063 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4065 break;
4067 case WINED3DRS_COLORVERTEX :
4068 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4069 case WINED3DRS_SPECULARMATERIALSOURCE :
4070 case WINED3DRS_AMBIENTMATERIALSOURCE :
4071 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4073 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4075 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4076 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4077 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4078 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4079 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4080 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4082 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4083 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4084 Parm = GL_AMBIENT_AND_DIFFUSE;
4085 } else {
4086 Parm = GL_DIFFUSE;
4088 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4089 Parm = GL_AMBIENT;
4090 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4091 Parm = GL_EMISSION;
4092 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4093 Parm = GL_SPECULAR;
4094 } else {
4095 Parm = -1;
4098 if (Parm == -1) {
4099 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4100 } else {
4101 This->tracking_color = NEEDS_TRACKING;
4102 This->tracking_parm = Parm;
4105 } else {
4106 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4109 break;
4111 case WINED3DRS_LINEPATTERN :
4113 union {
4114 DWORD d;
4115 D3DLINEPATTERN lp;
4116 } tmppattern;
4117 tmppattern.d = Value;
4119 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4121 if (tmppattern.lp.wRepeatFactor) {
4122 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4123 checkGLcall("glLineStipple(repeat, linepattern)");
4124 glEnable(GL_LINE_STIPPLE);
4125 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4126 } else {
4127 glDisable(GL_LINE_STIPPLE);
4128 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4131 break;
4133 case WINED3DRS_ZBIAS : /* D3D8 only */
4135 if (Value) {
4136 tmpvalue.d = Value;
4137 TRACE("ZBias value %f\n", tmpvalue.f);
4138 glPolygonOffset(0, -tmpvalue.f);
4139 checkGLcall("glPolygonOffset(0, -Value)");
4140 glEnable(GL_POLYGON_OFFSET_FILL);
4141 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4142 glEnable(GL_POLYGON_OFFSET_LINE);
4143 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4144 glEnable(GL_POLYGON_OFFSET_POINT);
4145 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4146 } else {
4147 glDisable(GL_POLYGON_OFFSET_FILL);
4148 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4149 glDisable(GL_POLYGON_OFFSET_LINE);
4150 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4151 glDisable(GL_POLYGON_OFFSET_POINT);
4152 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4155 break;
4157 case WINED3DRS_NORMALIZENORMALS :
4158 if (Value) {
4159 glEnable(GL_NORMALIZE);
4160 checkGLcall("glEnable(GL_NORMALIZE);");
4161 } else {
4162 glDisable(GL_NORMALIZE);
4163 checkGLcall("glDisable(GL_NORMALIZE);");
4165 break;
4167 case WINED3DRS_POINTSIZE :
4168 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4169 tmpvalue.d = Value;
4170 TRACE("Set point size to %f\n", tmpvalue.f);
4171 glPointSize(tmpvalue.f);
4172 checkGLcall("glPointSize(...);");
4173 break;
4175 case WINED3DRS_POINTSIZE_MIN :
4176 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4177 tmpvalue.d = Value;
4178 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4179 checkGLcall("glPointParameterfEXT(...);");
4180 } else {
4181 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4183 break;
4185 case WINED3DRS_POINTSIZE_MAX :
4186 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4187 tmpvalue.d = Value;
4188 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4189 checkGLcall("glPointParameterfEXT(...);");
4190 } else {
4191 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4193 break;
4195 case WINED3DRS_POINTSCALE_A :
4196 case WINED3DRS_POINTSCALE_B :
4197 case WINED3DRS_POINTSCALE_C :
4198 case WINED3DRS_POINTSCALEENABLE :
4201 * POINTSCALEENABLE controls how point size value is treated. If set to
4202 * true, the point size is scaled with respect to height of viewport.
4203 * When set to false point size is in pixels.
4205 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4208 /* Default values */
4209 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4212 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4213 * This means that OpenGL will clamp really small point sizes to 1.0f.
4214 * To correct for this we need to multiply by the scale factor when sizes
4215 * are less than 1.0f. scale_factor = 1.0f / point_size.
4217 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4218 if(pointSize > 0.0f) {
4219 GLfloat scaleFactor;
4221 if(pointSize < 1.0f) {
4222 scaleFactor = pointSize * pointSize;
4223 } else {
4224 scaleFactor = 1.0f;
4227 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4228 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4229 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4230 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4231 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4232 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4233 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4237 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4238 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4239 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4241 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4242 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4243 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4244 } else {
4245 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4247 break;
4249 case WINED3DRS_COLORWRITEENABLE :
4251 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4252 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4253 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4254 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4255 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4256 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4257 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4258 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4259 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4260 checkGLcall("glColorMask(...)");
4262 break;
4264 case WINED3DRS_LOCALVIEWER :
4266 GLint state = (Value) ? 1 : 0;
4267 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4268 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4270 break;
4272 case WINED3DRS_LASTPIXEL :
4274 if (Value) {
4275 TRACE("Last Pixel Drawing Enabled\n");
4276 } else {
4277 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4280 break;
4282 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4284 if (Value) {
4285 TRACE("Software Processing Enabled\n");
4286 } else {
4287 TRACE("Software Processing Disabled\n");
4290 break;
4292 /** not supported */
4293 case WINED3DRS_ZVISIBLE :
4295 LEAVE_GL();
4296 return WINED3DERR_INVALIDCALL;
4298 case WINED3DRS_POINTSPRITEENABLE :
4300 /* TODO: NV_POINT_SPRITE */
4301 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4302 TRACE("Point sprites not supported\n");
4303 break;
4307 * Point sprites are always enabled. Value controls texture coordinate
4308 * replacement mode. Must be set true for point sprites to use
4309 * textures.
4311 glEnable(GL_POINT_SPRITE_ARB);
4312 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4314 if (Value) {
4315 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4316 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4317 } else {
4318 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4319 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4321 break;
4323 case WINED3DRS_EDGEANTIALIAS :
4325 if(Value) {
4326 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4327 glEnable(GL_BLEND);
4328 checkGLcall("glEnable(GL_BLEND)");
4329 glEnable(GL_LINE_SMOOTH);
4330 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4331 } else {
4332 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4333 glDisable(GL_BLEND);
4334 checkGLcall("glDisable(GL_BLEND)");
4336 glDisable(GL_LINE_SMOOTH);
4337 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4339 break;
4341 case WINED3DRS_WRAP0 :
4342 case WINED3DRS_WRAP1 :
4343 case WINED3DRS_WRAP2 :
4344 case WINED3DRS_WRAP3 :
4345 case WINED3DRS_WRAP4 :
4346 case WINED3DRS_WRAP5 :
4347 case WINED3DRS_WRAP6 :
4348 case WINED3DRS_WRAP7 :
4349 case WINED3DRS_WRAP8 :
4350 case WINED3DRS_WRAP9 :
4351 case WINED3DRS_WRAP10 :
4352 case WINED3DRS_WRAP11 :
4353 case WINED3DRS_WRAP12 :
4354 case WINED3DRS_WRAP13 :
4355 case WINED3DRS_WRAP14 :
4356 case WINED3DRS_WRAP15 :
4358 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4359 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4360 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4361 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4362 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4364 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4366 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4367 break;
4368 case WINED3DRS_MULTISAMPLEANTIALIAS :
4370 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4371 TRACE("Multisample antialiasing not supported\n");
4372 break;
4375 if(Value) {
4376 glEnable(GL_MULTISAMPLE_ARB);
4377 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4378 } else {
4379 glDisable(GL_MULTISAMPLE_ARB);
4380 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4382 break;
4384 case WINED3DRS_SCISSORTESTENABLE :
4386 if(Value) {
4387 glEnable(GL_SCISSOR_TEST);
4388 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4389 } else {
4390 glDisable(GL_SCISSOR_TEST);
4391 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4393 break;
4395 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4397 if(Value) {
4398 tmpvalue.d = Value;
4399 glEnable(GL_POLYGON_OFFSET_FILL);
4400 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4401 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4402 checkGLcall("glPolygonOffset(...)");
4403 } else {
4404 glDisable(GL_POLYGON_OFFSET_FILL);
4405 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4407 break;
4409 case WINED3DRS_ANTIALIASEDLINEENABLE :
4411 if(Value) {
4412 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4413 glEnable(GL_BLEND);
4414 checkGLcall("glEnable(GL_BLEND)");
4415 glEnable(GL_LINE_SMOOTH);
4416 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4417 } else {
4418 glDisable(GL_BLEND);
4419 checkGLcall("glDisable(GL_BLEND)");
4420 glDisable(GL_LINE_SMOOTH);
4421 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4423 break;
4425 case WINED3DRS_DEPTHBIAS :
4427 if(Value) {
4428 tmpvalue.d = Value;
4429 glEnable(GL_POLYGON_OFFSET_FILL);
4430 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4431 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4432 checkGLcall("glPolygonOffset(...)");
4433 } else {
4434 glDisable(GL_POLYGON_OFFSET_FILL);
4435 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4437 break;
4440 case WINED3DRS_TEXTUREPERSPECTIVE :
4442 if (Value)
4443 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4444 else
4445 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4446 break;
4449 case WINED3DRS_STIPPLEDALPHA :
4451 if (Value)
4452 ERR(" Stippled Alpha not supported yet.\n");
4453 break;
4455 case WINED3DRS_ANTIALIAS :
4457 if (Value)
4458 ERR(" Antialias not supported yet.\n");
4459 break;
4461 default:
4462 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4465 LEAVE_GL();
4467 return WINED3D_OK;
4470 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4473 *pValue = This->stateBlock->renderState[State];
4474 return WINED3D_OK;
4477 /*****
4478 * Get / Set Sampler States
4479 * TODO: Verify against dx9 definitions
4480 *****/
4482 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 * SetSampler is designed to allow for more than the standard up to 8 textures
4486 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4487 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4489 * http://developer.nvidia.com/object/General_FAQ.html#t6
4491 * There are two new settings for GForce
4492 * the sampler one:
4493 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4494 * and the texture one:
4495 * GL_MAX_TEXTURE_COORDS_ARB.
4496 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4497 ******************/
4498 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4499 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4500 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4501 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4502 return WINED3DERR_INVALIDCALL;
4505 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4506 debug_d3dsamplerstate(Type), Type, Value);
4507 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4508 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4509 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4511 /* Handle recording of state blocks */
4512 if (This->isRecordingState) {
4513 TRACE("Recording... not performing anything\n");
4514 return WINED3D_OK;
4517 return WINED3D_OK;
4520 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 /** TODO: check that sampler is in range **/
4523 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4524 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4526 return WINED3D_OK;
4529 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4531 ENTER_GL();
4533 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4534 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4535 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4536 LEAVE_GL();
4538 return WINED3D_OK;
4541 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 GLint scissorBox[4];
4545 ENTER_GL();
4546 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4547 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4548 pRect->left = scissorBox[0];
4549 pRect->top = scissorBox[1];
4550 pRect->right = scissorBox[0] + scissorBox[2];
4551 pRect->bottom = scissorBox[1] + scissorBox[3];
4552 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4553 LEAVE_GL();
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4559 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4561 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4563 This->updateStateBlock->vertexDecl = pDecl;
4564 This->updateStateBlock->changed.vertexDecl = TRUE;
4565 This->updateStateBlock->set.vertexDecl = TRUE;
4567 if (This->isRecordingState) {
4568 TRACE("Recording... not performing anything\n");
4571 if (NULL != pDecl) {
4572 IWineD3DVertexDeclaration_AddRef(pDecl);
4574 if (NULL != oldDecl) {
4575 IWineD3DVertexDeclaration_Release(oldDecl);
4577 return WINED3D_OK;
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4585 *ppDecl = This->stateBlock->vertexDecl;
4586 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4587 return WINED3D_OK;
4590 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4592 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4594 This->updateStateBlock->vertexShader = pShader;
4595 This->updateStateBlock->changed.vertexShader = TRUE;
4596 This->updateStateBlock->set.vertexShader = TRUE;
4598 if (This->isRecordingState) {
4599 TRACE("Recording... not performing anything\n");
4602 if (NULL != pShader) {
4603 IWineD3DVertexShader_AddRef(pShader);
4605 if (NULL != oldShader) {
4606 IWineD3DVertexShader_Release(oldShader);
4609 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4611 * TODO: merge HAL shaders context switching from prototype
4613 return WINED3D_OK;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4619 if (NULL == ppShader) {
4620 return WINED3DERR_INVALIDCALL;
4622 *ppShader = This->stateBlock->vertexShader;
4623 if( NULL != *ppShader)
4624 IWineD3DVertexShader_AddRef(*ppShader);
4626 TRACE("(%p) : returning %p\n", This, *ppShader);
4627 return WINED3D_OK;
4630 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4631 IWineD3DDevice *iface,
4632 UINT start,
4633 CONST BOOL *srcData,
4634 UINT count) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4637 int i, cnt = min(count, MAX_CONST_B - start);
4639 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4640 iface, srcData, start, count);
4642 if (srcData == NULL || cnt < 0)
4643 return WINED3DERR_INVALIDCALL;
4645 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4646 for (i = 0; i < cnt; i++)
4647 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4649 for (i = start; i < cnt + start; ++i) {
4650 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4651 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4654 return WINED3D_OK;
4657 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4658 IWineD3DDevice *iface,
4659 UINT start,
4660 BOOL *dstData,
4661 UINT count) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 int cnt = min(count, MAX_CONST_B - start);
4666 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4667 iface, dstData, start, count);
4669 if (dstData == NULL || cnt < 0)
4670 return WINED3DERR_INVALIDCALL;
4672 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4673 return WINED3D_OK;
4676 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4677 IWineD3DDevice *iface,
4678 UINT start,
4679 CONST int *srcData,
4680 UINT count) {
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 int i, cnt = min(count, MAX_CONST_I - start);
4685 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4686 iface, srcData, start, count);
4688 if (srcData == NULL || cnt < 0)
4689 return WINED3DERR_INVALIDCALL;
4691 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4692 for (i = 0; i < cnt; i++)
4693 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4694 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4696 for (i = start; i < cnt + start; ++i) {
4697 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4698 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4701 return WINED3D_OK;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4705 IWineD3DDevice *iface,
4706 UINT start,
4707 int *dstData,
4708 UINT count) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 int cnt = min(count, MAX_CONST_I - start);
4713 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4714 iface, dstData, start, count);
4716 if (dstData == NULL || cnt < 0)
4717 return WINED3DERR_INVALIDCALL;
4719 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4720 return WINED3D_OK;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4724 IWineD3DDevice *iface,
4725 UINT start,
4726 CONST float *srcData,
4727 UINT count) {
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4732 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4733 iface, srcData, start, count);
4735 if (srcData == NULL || cnt < 0)
4736 return WINED3DERR_INVALIDCALL;
4738 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4739 for (i = 0; i < cnt; i++)
4740 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4741 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4743 for (i = start; i < cnt + start; ++i) {
4744 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4745 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4748 return WINED3D_OK;
4751 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4752 IWineD3DDevice *iface,
4753 UINT start,
4754 float *dstData,
4755 UINT count) {
4757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4758 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4760 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4761 iface, dstData, start, count);
4763 if (dstData == NULL || cnt < 0)
4764 return WINED3DERR_INVALIDCALL;
4766 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4767 return WINED3D_OK;
4770 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4773 This->updateStateBlock->pixelShader = pShader;
4774 This->updateStateBlock->changed.pixelShader = TRUE;
4775 This->updateStateBlock->set.pixelShader = TRUE;
4777 /* Handle recording of state blocks */
4778 if (This->isRecordingState) {
4779 TRACE("Recording... not performing anything\n");
4782 if (NULL != pShader) {
4783 IWineD3DPixelShader_AddRef(pShader);
4785 if (NULL != oldShader) {
4786 IWineD3DPixelShader_Release(oldShader);
4789 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4791 * TODO: merge HAL shaders context switching from prototype
4793 return WINED3D_OK;
4796 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4799 if (NULL == ppShader) {
4800 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4801 return WINED3DERR_INVALIDCALL;
4804 *ppShader = This->stateBlock->pixelShader;
4805 if (NULL != *ppShader) {
4806 IWineD3DPixelShader_AddRef(*ppShader);
4808 TRACE("(%p) : returning %p\n", This, *ppShader);
4809 return WINED3D_OK;
4812 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4813 IWineD3DDevice *iface,
4814 UINT start,
4815 CONST BOOL *srcData,
4816 UINT count) {
4818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4819 int i, cnt = min(count, MAX_CONST_B - start);
4821 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4822 iface, srcData, start, count);
4824 if (srcData == NULL || cnt < 0)
4825 return WINED3DERR_INVALIDCALL;
4827 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4828 for (i = 0; i < cnt; i++)
4829 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4831 for (i = start; i < cnt + start; ++i) {
4832 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4833 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4840 IWineD3DDevice *iface,
4841 UINT start,
4842 BOOL *dstData,
4843 UINT count) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 int cnt = min(count, MAX_CONST_B - start);
4848 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4849 iface, dstData, start, count);
4851 if (dstData == NULL || cnt < 0)
4852 return WINED3DERR_INVALIDCALL;
4854 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4855 return WINED3D_OK;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4859 IWineD3DDevice *iface,
4860 UINT start,
4861 CONST int *srcData,
4862 UINT count) {
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 int i, cnt = min(count, MAX_CONST_I - start);
4867 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4868 iface, srcData, start, count);
4870 if (srcData == NULL || cnt < 0)
4871 return WINED3DERR_INVALIDCALL;
4873 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4874 for (i = 0; i < cnt; i++)
4875 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4876 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4878 for (i = start; i < cnt + start; ++i) {
4879 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4880 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4883 return WINED3D_OK;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4887 IWineD3DDevice *iface,
4888 UINT start,
4889 int *dstData,
4890 UINT count) {
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4893 int cnt = min(count, MAX_CONST_I - start);
4895 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4896 iface, dstData, start, count);
4898 if (dstData == NULL || cnt < 0)
4899 return WINED3DERR_INVALIDCALL;
4901 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4902 return WINED3D_OK;
4905 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4906 IWineD3DDevice *iface,
4907 UINT start,
4908 CONST float *srcData,
4909 UINT count) {
4911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4912 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4914 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4915 iface, srcData, start, count);
4917 if (srcData == NULL || cnt < 0)
4918 return WINED3DERR_INVALIDCALL;
4920 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4921 for (i = 0; i < cnt; i++)
4922 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4923 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4925 for (i = start; i < cnt + start; ++i) {
4926 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4927 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4930 return WINED3D_OK;
4933 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4934 IWineD3DDevice *iface,
4935 UINT start,
4936 float *dstData,
4937 UINT count) {
4939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4940 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4942 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4943 iface, dstData, start, count);
4945 if (dstData == NULL || cnt < 0)
4946 return WINED3DERR_INVALIDCALL;
4948 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4949 return WINED3D_OK;
4952 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4953 static HRESULT
4954 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4955 char *dest_ptr, *dest_conv = NULL;
4956 unsigned int i;
4957 DWORD DestFVF = dest->fvf;
4958 D3DVIEWPORT9 vp;
4959 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4960 BOOL doClip;
4961 int numTextures;
4963 if (SrcFVF & D3DFVF_NORMAL) {
4964 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4967 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4968 ERR("Source has no position mask\n");
4969 return WINED3DERR_INVALIDCALL;
4972 /* We might access VBOs from this code, so hold the lock */
4973 ENTER_GL();
4975 if (dest->resource.allocatedMemory == NULL) {
4976 /* This may happen if we do direct locking into a vbo. Unlikely,
4977 * but theoretically possible(ddraw processvertices test)
4979 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4980 if(!dest->resource.allocatedMemory) {
4981 LEAVE_GL();
4982 ERR("Out of memory\n");
4983 return E_OUTOFMEMORY;
4985 if(dest->vbo) {
4986 void *src;
4987 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4988 checkGLcall("glBindBufferARB");
4989 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4990 if(src) {
4991 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4993 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4994 checkGLcall("glUnmapBufferARB");
4998 /* Get a pointer into the destination vbo(create one if none exists) and
4999 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5001 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5002 CreateVBO(dest);
5005 if(dest->vbo) {
5006 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5007 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5008 if(!dest_conv) {
5009 ERR("glMapBuffer failed\n");
5010 /* Continue without storing converted vertices */
5014 /* Should I clip?
5015 * a) D3DRS_CLIPPING is enabled
5016 * b) WINED3DVOP_CLIP is passed
5018 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5019 static BOOL warned = FALSE;
5021 * The clipping code is not quite correct. Some things need
5022 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5023 * so disable clipping for now.
5024 * (The graphics in Half-Life are broken, and my processvertices
5025 * test crashes with IDirect3DDevice3)
5026 doClip = TRUE;
5028 doClip = FALSE;
5029 if(!warned) {
5030 warned = TRUE;
5031 FIXME("Clipping is broken and disabled for now\n");
5033 } else doClip = FALSE;
5034 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5035 if(dest_conv) {
5036 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5039 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5040 WINED3DTS_VIEW,
5041 &view_mat);
5042 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5043 WINED3DTS_PROJECTION,
5044 &proj_mat);
5045 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5046 WINED3DTS_WORLDMATRIX(0),
5047 &world_mat);
5049 TRACE("View mat:\n");
5050 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); \
5051 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); \
5052 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); \
5053 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); \
5055 TRACE("Proj mat:\n");
5056 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); \
5057 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); \
5058 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); \
5059 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); \
5061 TRACE("World mat:\n");
5062 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); \
5063 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); \
5064 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); \
5065 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); \
5067 /* Get the viewport */
5068 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5069 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5070 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5072 multiply_matrix(&mat,&view_mat,&world_mat);
5073 multiply_matrix(&mat,&proj_mat,&mat);
5075 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5077 for (i = 0; i < dwCount; i+= 1) {
5078 unsigned int tex_index;
5080 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5081 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5082 /* The position first */
5083 float *p =
5084 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5085 float x, y, z, rhw;
5086 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5088 /* Multiplication with world, view and projection matrix */
5089 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);
5090 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);
5091 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);
5092 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);
5094 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5096 /* WARNING: The following things are taken from d3d7 and were not yet checked
5097 * against d3d8 or d3d9!
5100 /* Clipping conditions: From
5101 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5103 * A vertex is clipped if it does not match the following requirements
5104 * -rhw < x <= rhw
5105 * -rhw < y <= rhw
5106 * 0 < z <= rhw
5107 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5109 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5110 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5114 if( doClip == FALSE ||
5115 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5116 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5117 ( rhw > eps ) ) ) {
5119 /* "Normal" viewport transformation (not clipped)
5120 * 1) The values are divided by rhw
5121 * 2) The y axis is negative, so multiply it with -1
5122 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5123 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5124 * 4) Multiply x with Width/2 and add Width/2
5125 * 5) The same for the height
5126 * 6) Add the viewpoint X and Y to the 2D coordinates and
5127 * The minimum Z value to z
5128 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5130 * Well, basically it's simply a linear transformation into viewport
5131 * coordinates
5134 x /= rhw;
5135 y /= rhw;
5136 z /= rhw;
5138 y *= -1;
5140 x *= vp.Width / 2;
5141 y *= vp.Height / 2;
5142 z *= vp.MaxZ - vp.MinZ;
5144 x += vp.Width / 2 + vp.X;
5145 y += vp.Height / 2 + vp.Y;
5146 z += vp.MinZ;
5148 rhw = 1 / rhw;
5149 } else {
5150 /* That vertex got clipped
5151 * Contrary to OpenGL it is not dropped completely, it just
5152 * undergoes a different calculation.
5154 TRACE("Vertex got clipped\n");
5155 x += rhw;
5156 y += rhw;
5158 x /= 2;
5159 y /= 2;
5161 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5162 * outside of the main vertex buffer memory. That needs some more
5163 * investigation...
5167 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5170 ( (float *) dest_ptr)[0] = x;
5171 ( (float *) dest_ptr)[1] = y;
5172 ( (float *) dest_ptr)[2] = z;
5173 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5175 dest_ptr += 3 * sizeof(float);
5177 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5178 dest_ptr += sizeof(float);
5181 if(dest_conv) {
5182 float w = 1 / rhw;
5183 ( (float *) dest_conv)[0] = x * w;
5184 ( (float *) dest_conv)[1] = y * w;
5185 ( (float *) dest_conv)[2] = z * w;
5186 ( (float *) dest_conv)[3] = w;
5188 dest_conv += 3 * sizeof(float);
5190 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5191 dest_conv += sizeof(float);
5195 if (DestFVF & D3DFVF_PSIZE) {
5196 dest_ptr += sizeof(DWORD);
5197 if(dest_conv) dest_conv += sizeof(DWORD);
5199 if (DestFVF & D3DFVF_NORMAL) {
5200 float *normal =
5201 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5202 /* AFAIK this should go into the lighting information */
5203 FIXME("Didn't expect the destination to have a normal\n");
5204 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5205 if(dest_conv) {
5206 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5210 if (DestFVF & D3DFVF_DIFFUSE) {
5211 DWORD *color_d =
5212 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5213 if(!color_d) {
5214 static BOOL warned = FALSE;
5216 if(warned == FALSE) {
5217 ERR("No diffuse color in source, but destination has one\n");
5218 warned = TRUE;
5221 *( (DWORD *) dest_ptr) = 0xffffffff;
5222 dest_ptr += sizeof(DWORD);
5224 if(dest_conv) {
5225 *( (DWORD *) dest_conv) = 0xffffffff;
5226 dest_conv += sizeof(DWORD);
5229 else {
5230 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5231 if(dest_conv) {
5232 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5233 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5234 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5235 dest_conv += sizeof(DWORD);
5240 if (DestFVF & D3DFVF_SPECULAR) {
5241 /* What's the color value in the feedback buffer? */
5242 DWORD *color_s =
5243 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5244 if(!color_s) {
5245 static BOOL warned = FALSE;
5247 if(warned == FALSE) {
5248 ERR("No specular color in source, but destination has one\n");
5249 warned = TRUE;
5252 *( (DWORD *) dest_ptr) = 0xFF000000;
5253 dest_ptr += sizeof(DWORD);
5255 if(dest_conv) {
5256 *( (DWORD *) dest_conv) = 0xFF000000;
5257 dest_conv += sizeof(DWORD);
5260 else {
5261 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5262 if(dest_conv) {
5263 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5264 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5265 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5266 dest_conv += sizeof(DWORD);
5271 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5272 float *tex_coord =
5273 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5274 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5275 if(!tex_coord) {
5276 ERR("No source texture, but destination requests one\n");
5277 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5278 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5280 else {
5281 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5282 if(dest_conv) {
5283 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5289 if(dest_conv) {
5290 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5291 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5294 LEAVE_GL();
5296 return WINED3D_OK;
5298 #undef copy_and_next
5300 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5303 WineDirect3DVertexStridedData strided;
5304 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5306 /* We don't need the source vbo because this buffer is only used as
5307 * a source for ProcessVertices. Avoid wasting resources by converting the
5308 * buffer and loading the VBO
5310 if(SrcImpl->vbo) {
5311 TRACE("Releaseing the source vbo, it won't be needed\n");
5313 if(!SrcImpl->resource.allocatedMemory) {
5314 /* Rescue the data from the buffer */
5315 void *src;
5316 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5317 if(!SrcImpl->resource.allocatedMemory) {
5318 ERR("Out of memory\n");
5319 return E_OUTOFMEMORY;
5322 ENTER_GL();
5323 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5324 checkGLcall("glBindBufferARB");
5326 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5327 if(src) {
5328 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5331 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5332 checkGLcall("glUnmapBufferARB");
5333 } else {
5334 ENTER_GL();
5337 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5338 checkGLcall("glBindBufferARB");
5339 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5340 checkGLcall("glDeleteBuffersARB");
5341 LEAVE_GL();
5343 SrcImpl->vbo = 0;
5346 memset(&strided, 0, sizeof(strided));
5347 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5349 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5352 /*****
5353 * Apply / Get / Set Texture Stage States
5354 * TODO: Verify against dx9 definitions
5355 *****/
5357 /* 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 */
5358 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5360 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5361 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5363 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5365 /* Check that the stage is within limits */
5366 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5367 TRACE("Attempt to access invalid texture rejected\n");
5368 return;
5371 ENTER_GL();
5373 switch (Type) {
5374 case WINED3DTSS_ALPHAOP :
5375 case WINED3DTSS_COLOROP :
5376 /* nothing to do as moved to drawprim for now */
5377 break;
5378 case WINED3DTSS_ADDRESSW :
5379 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5380 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5381 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5383 } else {
5384 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5385 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5386 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5387 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5389 #endif
5390 case WINED3DTSS_TEXCOORDINDEX :
5392 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5394 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5395 one flag, you can still specify an index value, which the system uses to
5396 determine the texture wrapping mode.
5397 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5398 means use the vertex position (camera-space) as the input texture coordinates
5399 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5400 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5401 to the TEXCOORDINDEX value */
5404 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5406 switch (Value & 0xFFFF0000) {
5407 case D3DTSS_TCI_PASSTHRU:
5408 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5409 glDisable(GL_TEXTURE_GEN_S);
5410 glDisable(GL_TEXTURE_GEN_T);
5411 glDisable(GL_TEXTURE_GEN_R);
5412 glDisable(GL_TEXTURE_GEN_Q);
5413 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5414 break;
5416 case D3DTSS_TCI_CAMERASPACEPOSITION:
5417 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5418 as the input texture coordinates for this stage's texture transformation. This
5419 equates roughly to EYE_LINEAR */
5421 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5422 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5423 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5424 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5425 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5427 glMatrixMode(GL_MODELVIEW);
5428 glPushMatrix();
5429 glLoadIdentity();
5430 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5431 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5432 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5433 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5434 glPopMatrix();
5436 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5437 glEnable(GL_TEXTURE_GEN_S);
5438 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5439 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5440 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5441 glEnable(GL_TEXTURE_GEN_T);
5442 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5443 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5444 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5445 glEnable(GL_TEXTURE_GEN_R);
5446 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5447 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5448 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5450 break;
5452 case D3DTSS_TCI_CAMERASPACENORMAL:
5454 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5455 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5456 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5457 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5458 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5459 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5461 glMatrixMode(GL_MODELVIEW);
5462 glPushMatrix();
5463 glLoadIdentity();
5464 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5465 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5466 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5467 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5468 glPopMatrix();
5470 glEnable(GL_TEXTURE_GEN_S);
5471 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5472 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5473 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5474 glEnable(GL_TEXTURE_GEN_T);
5475 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5476 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5477 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5478 glEnable(GL_TEXTURE_GEN_R);
5479 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5480 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5481 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5484 break;
5486 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5488 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5489 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5490 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5491 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5492 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5493 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5495 glMatrixMode(GL_MODELVIEW);
5496 glPushMatrix();
5497 glLoadIdentity();
5498 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5499 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5500 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5501 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5502 glPopMatrix();
5504 glEnable(GL_TEXTURE_GEN_S);
5505 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5506 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5507 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5508 glEnable(GL_TEXTURE_GEN_T);
5509 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5510 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5511 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5512 glEnable(GL_TEXTURE_GEN_R);
5513 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5514 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5515 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5518 break;
5520 /* Unhandled types: */
5521 default:
5522 /* Todo: */
5523 /* ? disable GL_TEXTURE_GEN_n ? */
5524 glDisable(GL_TEXTURE_GEN_S);
5525 glDisable(GL_TEXTURE_GEN_T);
5526 glDisable(GL_TEXTURE_GEN_R);
5527 glDisable(GL_TEXTURE_GEN_Q);
5528 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5529 break;
5532 break;
5534 /* Unhandled */
5535 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5536 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5537 break;
5539 case WINED3DTSS_BUMPENVMAT00 :
5540 case WINED3DTSS_BUMPENVMAT01 :
5541 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5542 break;
5543 case WINED3DTSS_BUMPENVMAT10 :
5544 case WINED3DTSS_BUMPENVMAT11 :
5545 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5546 break;
5548 case WINED3DTSS_BUMPENVLSCALE :
5549 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5550 break;
5552 case WINED3DTSS_BUMPENVLOFFSET :
5553 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5554 break;
5556 case WINED3DTSS_RESULTARG :
5557 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5558 break;
5560 default:
5561 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5562 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5565 LEAVE_GL();
5567 return;
5570 /*****
5571 * Get / Set Texture Stage States
5572 * TODO: Verify against dx9 definitions
5573 *****/
5574 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5579 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5581 /* Reject invalid texture units */
5582 if (Stage >= GL_LIMITS(texture_stages)) {
5583 TRACE("Attempt to access invalid texture rejected\n");
5584 return WINED3DERR_INVALIDCALL;
5587 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5588 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5589 This->updateStateBlock->textureState[Stage][Type] = Value;
5591 return WINED3D_OK;
5594 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5596 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5597 *pValue = This->updateStateBlock->textureState[Stage][Type];
5598 return WINED3D_OK;
5601 /*****
5602 * Get / Set Texture
5603 *****/
5604 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5607 IWineD3DBaseTexture *oldTexture;
5609 oldTexture = This->updateStateBlock->textures[Stage];
5610 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5612 #if 0 /* TODO: check so vertex textures */
5613 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5614 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5615 return WINED3D_OK;
5617 #endif
5619 /* Reject invalid texture units */
5620 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5621 WARN("Attempt to access invalid texture rejected\n");
5622 return WINED3DERR_INVALIDCALL;
5625 if(pTexture != NULL) {
5626 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5628 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5629 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5630 return WINED3DERR_INVALIDCALL;
5634 oldTexture = This->updateStateBlock->textures[Stage];
5635 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5636 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5638 This->updateStateBlock->set.textures[Stage] = TRUE;
5639 This->updateStateBlock->changed.textures[Stage] = TRUE;
5640 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5641 This->updateStateBlock->textures[Stage] = pTexture;
5643 /* Handle recording of state blocks */
5644 if (This->isRecordingState) {
5645 TRACE("Recording... not performing anything\n");
5646 return WINED3D_OK;
5649 /** NOTE: MSDN says that setTexture increases the reference count,
5650 * and the the application nust set the texture back to null (or have a leaky application),
5651 * This means we should pass the refcount up to the parent
5652 *******************************/
5653 if (NULL != This->updateStateBlock->textures[Stage]) {
5654 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5657 if (NULL != oldTexture) {
5658 IWineD3DBaseTexture_Release(oldTexture);
5661 /* Reset color keying */
5662 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5663 BOOL enable_ckey = FALSE;
5665 if(pTexture) {
5666 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5667 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5670 if(enable_ckey) {
5671 glAlphaFunc(GL_NOTEQUAL, 0.0);
5672 checkGLcall("glAlphaFunc");
5676 return WINED3D_OK;
5679 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5683 /* Reject invalid texture units */
5684 if (Stage >= GL_LIMITS(sampler_stages)) {
5685 TRACE("Attempt to access invalid texture rejected\n");
5686 return WINED3DERR_INVALIDCALL;
5688 *ppTexture=This->updateStateBlock->textures[Stage];
5689 if (*ppTexture)
5690 IWineD3DBaseTexture_AddRef(*ppTexture);
5691 else
5692 return WINED3DERR_INVALIDCALL;
5693 return WINED3D_OK;
5696 /*****
5697 * Get Back Buffer
5698 *****/
5699 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5700 IWineD3DSurface **ppBackBuffer) {
5701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5702 IWineD3DSwapChain *swapChain;
5703 HRESULT hr;
5705 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5707 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5708 if (hr == WINED3D_OK) {
5709 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5710 IWineD3DSwapChain_Release(swapChain);
5711 } else {
5712 *ppBackBuffer = NULL;
5714 return hr;
5717 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5719 WARN("(%p) : stub, calling idirect3d for now\n", This);
5720 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5723 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5725 IWineD3DSwapChain *swapChain;
5726 HRESULT hr;
5728 if(iSwapChain > 0) {
5729 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5730 if (hr == WINED3D_OK) {
5731 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5732 IWineD3DSwapChain_Release(swapChain);
5733 } else {
5734 FIXME("(%p) Error getting display mode\n", This);
5736 } else {
5737 /* Don't read the real display mode,
5738 but return the stored mode instead. X11 can't change the color
5739 depth, and some apps are pretty angry if they SetDisplayMode from
5740 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5742 Also don't relay to the swapchain because with ddraw it's possible
5743 that there isn't a swapchain at all */
5744 pMode->Width = This->ddraw_width;
5745 pMode->Height = This->ddraw_height;
5746 pMode->Format = This->ddraw_format;
5747 pMode->RefreshRate = 0;
5748 hr = WINED3D_OK;
5751 return hr;
5754 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5756 TRACE("(%p)->(%p)\n", This, hWnd);
5758 This->ddraw_window = hWnd;
5759 return WINED3D_OK;
5762 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 TRACE("(%p)->(%p)\n", This, hWnd);
5766 *hWnd = This->ddraw_window;
5767 return WINED3D_OK;
5770 /*****
5771 * Stateblock related functions
5772 *****/
5774 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 IWineD3DStateBlockImpl *object;
5777 HRESULT temp_result;
5779 TRACE("(%p)", This);
5781 if (This->isRecordingState) {
5782 return WINED3DERR_INVALIDCALL;
5785 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5786 if (NULL == object ) {
5787 FIXME("(%p)Error allocating memory for stateblock\n", This);
5788 return E_OUTOFMEMORY;
5790 TRACE("(%p) created object %p\n", This, object);
5791 object->wineD3DDevice= This;
5792 /** FIXME: object->parent = parent; **/
5793 object->parent = NULL;
5794 object->blockType = WINED3DSBT_ALL;
5795 object->ref = 1;
5796 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5798 temp_result = allocate_shader_constants(object);
5799 if (WINED3D_OK != temp_result)
5800 return temp_result;
5802 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5803 This->updateStateBlock = object;
5804 This->isRecordingState = TRUE;
5806 TRACE("(%p) recording stateblock %p\n",This , object);
5807 return WINED3D_OK;
5810 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5813 if (!This->isRecordingState) {
5814 FIXME("(%p) not recording! returning error\n", This);
5815 *ppStateBlock = NULL;
5816 return WINED3DERR_INVALIDCALL;
5819 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5820 This->isRecordingState = FALSE;
5821 This->updateStateBlock = This->stateBlock;
5822 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5823 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5824 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5825 return WINED3D_OK;
5828 /*****
5829 * Scene related functions
5830 *****/
5831 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5832 /* At the moment we have no need for any functionality at the beginning
5833 of a scene */
5834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 TRACE("(%p) : stub\n", This);
5836 return WINED3D_OK;
5839 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5841 TRACE("(%p)\n", This);
5842 ENTER_GL();
5843 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5844 glFlush();
5845 checkGLcall("glFlush");
5847 TRACE("End Scene\n");
5848 if(This->renderTarget != NULL) {
5850 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5851 IUnknown *targetContainer = NULL;
5852 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5853 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5854 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5855 /** always dirtify for now. we must find a better way to see that surface have been modified
5856 (Modifications should will only occur via draw-primitive, but we do need better locking
5857 switching to render-to-texture should remove the overhead though.
5859 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5860 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5861 IWineD3DSurface_PreLoad(This->renderTarget);
5862 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5863 IUnknown_Release(targetContainer);
5866 This->sceneEnded = TRUE;
5867 LEAVE_GL();
5868 return WINED3D_OK;
5871 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5872 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5873 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5875 IWineD3DSwapChain *swapChain = NULL;
5876 int i;
5877 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5879 TRACE("(%p) Presenting the frame\n", This);
5881 for(i = 0 ; i < swapchains ; i ++) {
5883 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5884 TRACE("presentinng chain %d, %p\n", i, swapChain);
5885 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5886 IWineD3DSwapChain_Release(swapChain);
5889 return WINED3D_OK;
5892 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5893 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5897 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5898 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5899 GLbitfield glMask = 0;
5900 GLboolean old_ztest;
5901 GLfloat old_z_clear_value;
5902 GLint old_stencil_clear_value;
5903 GLfloat old_color_clear_value[4];
5904 unsigned int i;
5905 CONST D3DRECT* curRect;
5907 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5908 Count, pRects, Flags, Z, Stencil);
5910 ENTER_GL();
5912 glEnable(GL_SCISSOR_TEST);
5913 checkGLcall("glEnable GL_SCISSOR_TEST");
5915 if (Count > 0 && pRects) {
5916 curRect = pRects;
5917 } else {
5918 curRect = NULL;
5921 /* Only set the values up once, as they are not changing */
5922 if (Flags & D3DCLEAR_STENCIL) {
5923 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5924 glClearStencil(Stencil);
5925 checkGLcall("glClearStencil");
5926 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5927 glStencilMask(0xFFFFFFFF);
5930 if (Flags & D3DCLEAR_ZBUFFER) {
5931 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5932 glDepthMask(GL_TRUE);
5933 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5934 glClearDepth(Z);
5935 checkGLcall("glClearDepth");
5936 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5939 if (Flags & D3DCLEAR_TARGET) {
5940 TRACE("Clearing screen with glClear to color %lx\n", Color);
5941 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5942 glClearColor(D3DCOLOR_R(Color),
5943 D3DCOLOR_G(Color),
5944 D3DCOLOR_B(Color),
5945 D3DCOLOR_A(Color));
5946 checkGLcall("glClearColor");
5948 /* Clear ALL colors! */
5949 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5950 glMask = glMask | GL_COLOR_BUFFER_BIT;
5953 /* Now process each rect in turn */
5954 for (i = 0; i < Count || i == 0; i++) {
5956 if (curRect) {
5957 /* Note gl uses lower left, width/height */
5958 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5959 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5960 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5961 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5962 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5963 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5964 checkGLcall("glScissor");
5965 } else {
5966 glScissor(This->stateBlock->viewport.X,
5967 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5968 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5969 This->stateBlock->viewport.Width,
5970 This->stateBlock->viewport.Height);
5971 checkGLcall("glScissor");
5974 /* Clear the selected rectangle (or full screen) */
5975 glClear(glMask);
5976 checkGLcall("glClear");
5978 /* Step to the next rectangle */
5979 if (curRect) curRect = curRect + sizeof(D3DRECT);
5982 /* Restore the old values (why..?) */
5983 if (Flags & D3DCLEAR_STENCIL) {
5984 glClearStencil(old_stencil_clear_value);
5985 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5987 if (Flags & D3DCLEAR_ZBUFFER) {
5988 glDepthMask(old_ztest);
5989 glClearDepth(old_z_clear_value);
5991 if (Flags & D3DCLEAR_TARGET) {
5992 glClearColor(old_color_clear_value[0],
5993 old_color_clear_value[1],
5994 old_color_clear_value[2],
5995 old_color_clear_value[3]);
5996 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5997 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5998 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5999 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6002 glDisable(GL_SCISSOR_TEST);
6003 checkGLcall("glDisable");
6004 LEAVE_GL();
6006 return WINED3D_OK;
6009 /*****
6010 * Drawing functions
6011 *****/
6012 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6013 UINT PrimitiveCount) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 This->stateBlock->streamIsUP = FALSE;
6018 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6019 debug_d3dprimitivetype(PrimitiveType),
6020 StartVertex, PrimitiveCount);
6021 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6022 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6025 return WINED3D_OK;
6028 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6029 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6030 D3DPRIMITIVETYPE PrimitiveType,
6031 INT baseVIndex, UINT minIndex,
6032 UINT NumVertices, UINT startIndex, UINT primCount) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 UINT idxStride = 2;
6036 IWineD3DIndexBuffer *pIB;
6037 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6039 pIB = This->stateBlock->pIndexData;
6040 This->stateBlock->streamIsUP = FALSE;
6042 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6043 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6044 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6046 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6047 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6048 idxStride = 2;
6049 } else {
6050 idxStride = 4;
6053 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6054 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6056 return WINED3D_OK;
6059 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6060 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6061 UINT VertexStreamZeroStride) {
6062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6064 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6065 debug_d3dprimitivetype(PrimitiveType),
6066 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6068 /* release the stream source */
6069 if (This->stateBlock->streamSource[0] != NULL) {
6070 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6073 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6074 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6075 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6076 This->stateBlock->streamIsUP = TRUE;
6078 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6079 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6081 /* MSDN specifies stream zero settings must be set to NULL */
6082 This->stateBlock->streamStride[0] = 0;
6083 This->stateBlock->streamSource[0] = NULL;
6085 /*stream zero settings set to null at end, as per the msdn */
6086 return WINED3D_OK;
6089 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6090 UINT MinVertexIndex, UINT NumVertices,
6091 UINT PrimitiveCount, CONST void* pIndexData,
6092 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6093 UINT VertexStreamZeroStride) {
6094 int idxStride;
6095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6097 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6098 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6099 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6100 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6102 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6103 idxStride = 2;
6104 } else {
6105 idxStride = 4;
6108 /* release the stream and index data */
6109 if (This->stateBlock->streamSource[0] != NULL) {
6110 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6112 if (This->stateBlock->pIndexData) {
6113 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6116 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6117 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6118 This->stateBlock->streamIsUP = TRUE;
6119 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6121 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6123 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6124 This->stateBlock->streamSource[0] = NULL;
6125 This->stateBlock->streamStride[0] = 0;
6126 This->stateBlock->pIndexData = NULL;
6128 return WINED3D_OK;
6131 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6133 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6134 return WINED3D_OK;
6136 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6137 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6139 HRESULT hr = WINED3D_OK;
6140 WINED3DRESOURCETYPE sourceType;
6141 WINED3DRESOURCETYPE destinationType;
6142 int i ,levels;
6144 /* TODO: think about moving the code into IWineD3DBaseTexture */
6146 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6148 /* verify that the source and destination textures aren't NULL */
6149 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6150 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6151 This, pSourceTexture, pDestinationTexture);
6152 hr = WINED3DERR_INVALIDCALL;
6155 if (pSourceTexture == pDestinationTexture) {
6156 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6157 This, pSourceTexture, pDestinationTexture);
6158 hr = WINED3DERR_INVALIDCALL;
6160 /* Verify that the source and destination textures are the same type */
6161 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6162 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6164 if (sourceType != destinationType) {
6165 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6166 This);
6167 hr = WINED3DERR_INVALIDCALL;
6170 /* check that both textures have the identical numbers of levels */
6171 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6172 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6173 hr = WINED3DERR_INVALIDCALL;
6176 if (WINED3D_OK == hr) {
6178 /* Make sure that the destination texture is loaded */
6179 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6181 /* Update every surface level of the texture */
6182 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6184 switch (sourceType) {
6185 case WINED3DRTYPE_TEXTURE:
6187 IWineD3DSurface *srcSurface;
6188 IWineD3DSurface *destSurface;
6190 for (i = 0 ; i < levels ; ++i) {
6191 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6192 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6193 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6194 IWineD3DSurface_Release(srcSurface);
6195 IWineD3DSurface_Release(destSurface);
6196 if (WINED3D_OK != hr) {
6197 WARN("(%p) : Call to update surface failed\n", This);
6198 return hr;
6202 break;
6203 case WINED3DRTYPE_CUBETEXTURE:
6205 IWineD3DSurface *srcSurface;
6206 IWineD3DSurface *destSurface;
6207 WINED3DCUBEMAP_FACES faceType;
6209 for (i = 0 ; i < levels ; ++i) {
6210 /* Update each cube face */
6211 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6212 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6213 if (WINED3D_OK != hr) {
6214 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6215 } else {
6216 TRACE("Got srcSurface %p\n", srcSurface);
6218 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6219 if (WINED3D_OK != hr) {
6220 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6221 } else {
6222 TRACE("Got desrSurface %p\n", destSurface);
6224 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6225 IWineD3DSurface_Release(srcSurface);
6226 IWineD3DSurface_Release(destSurface);
6227 if (WINED3D_OK != hr) {
6228 WARN("(%p) : Call to update surface failed\n", This);
6229 return hr;
6234 break;
6235 #if 0 /* TODO: Add support for volume textures */
6236 case WINED3DRTYPE_VOLUMETEXTURE:
6238 IWineD3DVolume srcVolume = NULL;
6239 IWineD3DSurface destVolume = NULL;
6241 for (i = 0 ; i < levels ; ++i) {
6242 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6243 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6244 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6245 IWineD3DVolume_Release(srcSurface);
6246 IWineD3DVolume_Release(destSurface);
6247 if (WINED3D_OK != hr) {
6248 WARN("(%p) : Call to update volume failed\n", This);
6249 return hr;
6253 break;
6254 #endif
6255 default:
6256 FIXME("(%p) : Unsupported source and destination type\n", This);
6257 hr = WINED3DERR_INVALIDCALL;
6261 return hr;
6264 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6265 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6266 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6269 TRACE("(%p) : stub\n", This);
6270 return WINED3D_OK;
6272 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6274 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6275 * NOTE It may be best to move the code into surface to occomplish this
6276 ****************************************/
6278 WINED3DSURFACE_DESC surfaceDesc;
6279 unsigned int surfaceWidth, surfaceHeight;
6280 glDescriptor *targetGlDescription = NULL;
6281 glDescriptor *surfaceGlDescription = NULL;
6282 IWineD3DSwapChainImpl *container = NULL;
6284 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6285 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6286 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6288 surfaceDesc.Width = &surfaceWidth;
6289 surfaceDesc.Height = &surfaceHeight;
6290 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6291 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6293 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6294 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6295 ENTER_GL();
6296 /* TODO: opengl Context switching for swapchains etc... */
6297 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6298 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6299 glReadBuffer(GL_BACK);
6300 vcheckGLcall("glReadBuffer(GL_BACK)");
6301 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6302 glReadBuffer(GL_FRONT);
6303 vcheckGLcall("glReadBuffer(GL_FRONT)");
6304 } else if (pRenderTarget == This->depthStencilBuffer) {
6305 FIXME("Reading of depthstencil not yet supported\n");
6308 glReadPixels(surfaceGlDescription->target,
6309 surfaceGlDescription->level,
6310 surfaceWidth,
6311 surfaceHeight,
6312 surfaceGlDescription->glFormat,
6313 surfaceGlDescription->glType,
6314 (void *)IWineD3DSurface_GetData(pSurface));
6315 vcheckGLcall("glReadPixels(...)");
6316 if(NULL != container ){
6317 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6319 } else {
6320 IWineD3DBaseTexture *container;
6321 GLenum textureDimensions = GL_TEXTURE_2D;
6323 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6324 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6325 IWineD3DBaseTexture_Release(container);
6327 /* TODO: 2D -> Cube surface coppies etc.. */
6328 if (surfaceGlDescription->target != textureDimensions) {
6329 FIXME("(%p) : Texture dimension mismatch\n", This);
6331 glEnable(textureDimensions);
6332 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6333 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6334 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6335 vcheckGLcall("glBindTexture");
6336 glGetTexImage(surfaceGlDescription->target,
6337 surfaceGlDescription->level,
6338 surfaceGlDescription->glFormat,
6339 surfaceGlDescription->glType,
6340 (void *)IWineD3DSurface_GetData(pSurface));
6341 glDisable(textureDimensions);
6342 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6345 LEAVE_GL();
6346 return WINED3D_OK;
6349 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6350 IWineD3DSwapChain *swapChain;
6351 HRESULT hr;
6352 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6353 if(hr == WINED3D_OK) {
6354 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6355 IWineD3DSwapChain_Release(swapChain);
6357 return hr;
6360 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6362 /* return a sensible default */
6363 *pNumPasses = 1;
6364 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6365 FIXME("(%p) : stub\n", This);
6366 return WINED3D_OK;
6369 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6371 int j;
6372 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6373 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6374 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6375 return WINED3DERR_INVALIDCALL;
6377 for (j = 0; j < 256; ++j) {
6378 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6379 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6380 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6381 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6383 TRACE("(%p) : returning\n", This);
6384 return WINED3D_OK;
6387 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6389 int j;
6390 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6391 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6392 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6393 return WINED3DERR_INVALIDCALL;
6395 for (j = 0; j < 256; ++j) {
6396 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6397 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6398 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6399 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6401 TRACE("(%p) : returning\n", This);
6402 return WINED3D_OK;
6405 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6407 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6408 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6409 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6410 return WINED3DERR_INVALIDCALL;
6412 /*TODO: stateblocks */
6413 This->currentPalette = PaletteNumber;
6414 TRACE("(%p) : returning\n", This);
6415 return WINED3D_OK;
6418 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6420 if (PaletteNumber == NULL) {
6421 WARN("(%p) : returning Invalid Call\n", This);
6422 return WINED3DERR_INVALIDCALL;
6424 /*TODO: stateblocks */
6425 *PaletteNumber = This->currentPalette;
6426 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6427 return WINED3D_OK;
6430 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 static BOOL showFixmes = TRUE;
6433 if (showFixmes) {
6434 FIXME("(%p) : stub\n", This);
6435 showFixmes = FALSE;
6438 This->softwareVertexProcessing = bSoftware;
6439 return WINED3D_OK;
6443 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6445 static BOOL showFixmes = TRUE;
6446 if (showFixmes) {
6447 FIXME("(%p) : stub\n", This);
6448 showFixmes = FALSE;
6450 return This->softwareVertexProcessing;
6454 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6456 IWineD3DSwapChain *swapChain;
6457 HRESULT hr;
6459 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6461 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6462 if(hr == WINED3D_OK){
6463 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6464 IWineD3DSwapChain_Release(swapChain);
6465 }else{
6466 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6468 return hr;
6472 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6474 static BOOL showfixmes = TRUE;
6475 if(nSegments != 0.0f) {
6476 if( showfixmes) {
6477 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6478 showfixmes = FALSE;
6481 return WINED3D_OK;
6484 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6486 static BOOL showfixmes = TRUE;
6487 if( showfixmes) {
6488 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6489 showfixmes = FALSE;
6491 return 0.0f;
6494 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6496 /** TODO: remove casts to IWineD3DSurfaceImpl
6497 * NOTE: move code to surface to accomplish this
6498 ****************************************/
6499 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6500 int srcWidth, srcHeight;
6501 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6502 WINED3DFORMAT destFormat, srcFormat;
6503 UINT destSize;
6504 int destLeft, destTop;
6505 WINED3DPOOL srcPool, destPool;
6506 int offset = 0;
6507 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6508 glDescriptor *glDescription = NULL;
6509 GLenum textureDimensions = GL_TEXTURE_2D;
6510 IWineD3DBaseTexture *baseTexture;
6512 WINED3DSURFACE_DESC winedesc;
6514 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6515 memset(&winedesc, 0, sizeof(winedesc));
6516 winedesc.Width = &srcSurfaceWidth;
6517 winedesc.Height = &srcSurfaceHeight;
6518 winedesc.Pool = &srcPool;
6519 winedesc.Format = &srcFormat;
6521 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6523 winedesc.Width = &destSurfaceWidth;
6524 winedesc.Height = &destSurfaceHeight;
6525 winedesc.Pool = &destPool;
6526 winedesc.Format = &destFormat;
6527 winedesc.Size = &destSize;
6529 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6531 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6532 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6533 return WINED3DERR_INVALIDCALL;
6536 if (destFormat == WINED3DFMT_UNKNOWN) {
6537 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6538 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6540 /* Get the update surface description */
6541 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6544 /* Make sure the surface is loaded and up to date */
6545 IWineD3DSurface_PreLoad(pDestinationSurface);
6547 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6549 ENTER_GL();
6551 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6552 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6553 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6554 destLeft = pDestPoint ? pDestPoint->x : 0;
6555 destTop = pDestPoint ? pDestPoint->y : 0;
6558 /* This function doesn't support compressed textures
6559 the pitch is just bytesPerPixel * width */
6560 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6561 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6562 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6563 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6565 /* TODO DXT formats */
6567 if(pSourceRect != NULL && pSourceRect->top != 0){
6568 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6570 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6571 ,This
6572 ,glDescription->level
6573 ,destLeft
6574 ,destTop
6575 ,srcWidth
6576 ,srcHeight
6577 ,glDescription->glFormat
6578 ,glDescription->glType
6579 ,IWineD3DSurface_GetData(pSourceSurface)
6582 /* Sanity check */
6583 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6585 /* need to lock the surface to get the data */
6586 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6589 /* TODO: Cube and volume support */
6590 if(rowoffset != 0){
6591 /* not a whole row so we have to do it a line at a time */
6592 int j;
6594 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6595 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6597 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6599 glTexSubImage2D(glDescription->target
6600 ,glDescription->level
6601 ,destLeft
6603 ,srcWidth
6605 ,glDescription->glFormat
6606 ,glDescription->glType
6607 ,data /* could be quicker using */
6609 data += rowoffset;
6612 } else { /* Full width, so just write out the whole texture */
6614 if (WINED3DFMT_DXT1 == destFormat ||
6615 WINED3DFMT_DXT2 == destFormat ||
6616 WINED3DFMT_DXT3 == destFormat ||
6617 WINED3DFMT_DXT4 == destFormat ||
6618 WINED3DFMT_DXT5 == destFormat) {
6619 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6620 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6621 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6622 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6623 } if (destFormat != srcFormat) {
6624 FIXME("Updating mixed format compressed texture is not curretly support\n");
6625 } else {
6626 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6627 glDescription->level,
6628 glDescription->glFormatInternal,
6629 srcWidth,
6630 srcHeight,
6632 destSize,
6633 IWineD3DSurface_GetData(pSourceSurface));
6635 } else {
6636 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6640 } else {
6641 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6643 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6644 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6645 data returned by GetData non-power2 width/height with hardware non-power2
6646 pow2Width/height are set to surface width height, repacking isn't needed so it
6647 doesn't matter which function gets called. */
6648 glTexSubImage2D(glDescription->target
6649 ,glDescription->level
6650 ,destLeft
6651 ,destTop
6652 ,srcWidth
6653 ,srcHeight
6654 ,glDescription->glFormat
6655 ,glDescription->glType
6656 ,IWineD3DSurface_GetData(pSourceSurface)
6658 } else {
6660 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6661 glTexSubImage2D(glDescription->target
6662 ,glDescription->level
6663 ,destLeft
6664 ,destTop
6665 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6666 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6667 ,glDescription->glFormat
6668 ,glDescription->glType
6669 ,IWineD3DSurface_GetData(pSourceSurface)
6675 checkGLcall("glTexSubImage2D");
6677 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6678 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6679 * surface bigger than it needs to be hmm.. */
6680 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6681 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6682 IWineD3DBaseTexture_Release(baseTexture);
6685 glDisable(textureDimensions); /* This needs to be managed better.... */
6686 LEAVE_GL();
6688 return WINED3D_OK;
6691 /* Used by DirectX 8 */
6692 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6693 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6694 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6697 HRESULT hr = WINED3D_OK;
6698 WINED3DFORMAT srcFormat, destFormat;
6699 UINT srcWidth, destWidth;
6700 UINT srcHeight, destHeight;
6701 UINT srcSize;
6702 WINED3DSURFACE_DESC winedesc;
6704 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6705 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6708 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6709 memset(&winedesc, 0, sizeof(winedesc));
6711 winedesc.Format = &srcFormat;
6712 winedesc.Width = &srcWidth;
6713 winedesc.Height = &srcHeight;
6714 winedesc.Size = &srcSize;
6715 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6717 winedesc.Format = &destFormat;
6718 winedesc.Width = &destWidth;
6719 winedesc.Height = &destHeight;
6720 winedesc.Size = NULL;
6721 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6723 /* Check that the source and destination formats match */
6724 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6725 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6726 return WINED3DERR_INVALIDCALL;
6727 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6728 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6729 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6730 destFormat = srcFormat;
6733 /* Quick if complete copy ... */
6734 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6736 if (srcWidth == destWidth && srcHeight == destHeight) {
6737 WINED3DLOCKED_RECT lrSrc;
6738 WINED3DLOCKED_RECT lrDst;
6739 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6740 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6741 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6743 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6745 IWineD3DSurface_UnlockRect(pSourceSurface);
6746 IWineD3DSurface_UnlockRect(pDestinationSurface);
6747 TRACE("Unlocked src and dst\n");
6749 } else {
6751 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6752 hr = WINED3DERR_INVALIDCALL;
6755 } else {
6757 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6759 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6760 unsigned int i;
6762 /* Copy rect by rect */
6763 for (i = 0; i < cRects; ++i) {
6764 CONST RECT* r = &pSourceRectsArray[i];
6765 CONST POINT* p = &pDestPointsArray[i];
6766 int copyperline;
6767 int j;
6768 WINED3DLOCKED_RECT lrSrc;
6769 WINED3DLOCKED_RECT lrDst;
6770 RECT dest_rect;
6772 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6773 if (srcFormat == WINED3DFMT_DXT1) {
6774 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6775 } else {
6776 copyperline = ((r->right - r->left) * bytesPerPixel);
6779 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6780 dest_rect.left = p->x;
6781 dest_rect.top = p->y;
6782 dest_rect.right = p->x + (r->right - r->left);
6783 dest_rect.bottom= p->y + (r->bottom - r->top);
6784 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6785 TRACE("Locked src and dst\n");
6787 /* Find where to start */
6788 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6789 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6791 IWineD3DSurface_UnlockRect(pSourceSurface);
6792 IWineD3DSurface_UnlockRect(pDestinationSurface);
6793 TRACE("Unlocked src and dst\n");
6795 } else {
6796 unsigned int i;
6797 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6798 int copyperline;
6799 int j;
6800 WINED3DLOCKED_RECT lrSrc;
6801 WINED3DLOCKED_RECT lrDst;
6802 RECT dest_rect;
6804 for(i=0; i < cRects; i++) {
6805 CONST RECT* r = &pSourceRectsArray[i];
6807 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6808 if (srcFormat == WINED3DFMT_DXT1) {
6809 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6810 } else {
6811 copyperline = ((r->right - r->left) * bytesPerPixel);
6813 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6814 dest_rect.left = 0;
6815 dest_rect.top = 0;
6816 dest_rect.right = r->right - r->left;
6817 dest_rect.bottom= r->bottom - r->top;
6818 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6819 TRACE("Locked src and dst\n");
6820 /* Find where to start */
6821 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6822 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6824 IWineD3DSurface_UnlockRect(pSourceSurface);
6825 IWineD3DSurface_UnlockRect(pDestinationSurface);
6826 TRACE("Unlocked src and dst\n");
6831 return hr;
6834 /* Implementation details at http://developer.nvidia.com/attach/6494
6836 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6837 hmm.. no longer supported use
6838 OpenGL evaluators or tessellate surfaces within your application.
6841 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6842 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6844 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6845 FIXME("(%p) : Stub\n", This);
6846 return WINED3D_OK;
6850 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6851 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6853 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6854 FIXME("(%p) : Stub\n", This);
6855 return WINED3D_OK;
6858 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6860 TRACE("(%p) Handle(%d)\n", This, Handle);
6861 FIXME("(%p) : Stub\n", This);
6862 return WINED3D_OK;
6865 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6867 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6868 DDBLTFX BltFx;
6869 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6871 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6872 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6873 return WINED3DERR_INVALIDCALL;
6876 /* Just forward this to the DirectDraw blitting engine */
6877 memset(&BltFx, 0, sizeof(BltFx));
6878 BltFx.dwSize = sizeof(BltFx);
6879 BltFx.u5.dwFillColor = color;
6880 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6883 /* rendertarget and deptth stencil functions */
6884 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6887 /* FIXME: Implelent RenderTargetIndex >0 */
6888 if(RenderTargetIndex > 0)
6889 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6891 *ppRenderTarget = This->renderTarget;
6892 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6893 /* Note inc ref on returned surface */
6894 if(*ppRenderTarget != NULL)
6895 IWineD3DSurface_AddRef(*ppRenderTarget);
6896 return WINED3D_OK;
6899 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6901 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6902 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6903 IWineD3DSwapChainImpl *Swapchain;
6904 HRESULT hr;
6906 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6908 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6909 if(hr != WINED3D_OK) {
6910 ERR("Can't get the swapchain\n");
6911 return hr;
6914 /* Make sure to release the swapchain */
6915 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6917 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6918 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6919 return WINED3DERR_INVALIDCALL;
6921 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6922 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6923 return WINED3DERR_INVALIDCALL;
6926 if(Swapchain->frontBuffer != Front) {
6927 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6929 if(Swapchain->frontBuffer)
6930 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6931 Swapchain->frontBuffer = Front;
6933 if(Swapchain->frontBuffer) {
6934 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6938 if(Back && !Swapchain->backBuffer) {
6939 /* We need memory for the back buffer array - only one back buffer this way */
6940 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6941 if(!Swapchain->backBuffer) {
6942 ERR("Out of memory\n");
6943 return E_OUTOFMEMORY;
6947 if(Swapchain->backBuffer[0] != Back) {
6948 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6949 ENTER_GL();
6950 if(!Swapchain->backBuffer[0]) {
6951 /* GL was told to draw to the front buffer at creation,
6952 * undo that
6954 glDrawBuffer(GL_BACK);
6955 checkGLcall("glDrawBuffer(GL_BACK)");
6956 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6957 Swapchain->presentParms.BackBufferCount = 1;
6958 } else if (!Back) {
6959 /* That makes problems - disable for now */
6960 /* glDrawBuffer(GL_FRONT); */
6961 checkGLcall("glDrawBuffer(GL_FRONT)");
6962 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6963 Swapchain->presentParms.BackBufferCount = 0;
6965 LEAVE_GL();
6967 if(Swapchain->backBuffer[0])
6968 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6969 Swapchain->backBuffer[0] = Back;
6971 if(Swapchain->backBuffer[0]) {
6972 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6973 } else {
6974 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6979 return WINED3D_OK;
6982 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6984 *ppZStencilSurface = This->depthStencilBuffer;
6985 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6987 if(*ppZStencilSurface != NULL) {
6988 /* Note inc ref on returned surface */
6989 IWineD3DSurface_AddRef(*ppZStencilSurface);
6991 return WINED3D_OK;
6994 /* internal static helper functions */
6995 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6996 IWineD3DSurface *RenderSurface);
6998 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7000 HRESULT hr = WINED3D_OK;
7001 WINED3DVIEWPORT viewport;
7003 TRACE("(%p) Swapping rendertarget\n",This);
7004 if (RenderTargetIndex > 0) {
7005 FIXME("(%p) Render targets other than the first are not supported\n",This);
7006 RenderTargetIndex = 0;
7009 /* MSDN says that null disables the render target
7010 but a device must always be associated with a render target
7011 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7013 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7014 for more details
7016 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7017 FIXME("Trying to set render target 0 to NULL\n");
7018 return WINED3DERR_INVALIDCALL;
7020 /* TODO: replace Impl* usage with interface usage */
7021 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7022 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);
7023 return WINED3DERR_INVALIDCALL;
7025 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7026 * builds, but I think wine counts as a 'debug' build for now.
7027 ******************************/
7028 /* If we are trying to set what we already have, don't bother */
7029 if (pRenderTarget == This->renderTarget) {
7030 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7031 } else {
7032 /* Otherwise, set the render target up */
7034 if (FALSE == This->sceneEnded) {
7035 IWineD3DDevice_EndScene(iface);
7037 TRACE("clearing renderer\n");
7038 /* IWineD3DDeviceImpl_CleanRender(iface); */
7039 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7040 depending on the renter target implementation being used.
7041 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7042 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7043 stencil buffer and incure an extra memory overhead */
7044 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7047 if (SUCCEEDED(hr)) {
7048 /* Finally, reset the viewport as the MSDN states. */
7049 /* TODO: Replace impl usage */
7050 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7051 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7052 viewport.X = 0;
7053 viewport.Y = 0;
7054 viewport.MaxZ = 1.0f;
7055 viewport.MinZ = 0.0f;
7056 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7057 } else {
7058 FIXME("Unknown error setting the render target\n");
7060 This->sceneEnded = FALSE;
7061 return hr;
7064 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7066 HRESULT hr = WINED3D_OK;
7067 IWineD3DSurface *tmp;
7069 TRACE("(%p) Swapping z-buffer\n",This);
7071 if (pNewZStencil == This->stencilBufferTarget) {
7072 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7073 } else {
7074 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7075 * depending on the renter target implementation being used.
7076 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7077 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7078 * stencil buffer and incure an extra memory overhead
7079 ******************************************************/
7082 tmp = This->stencilBufferTarget;
7083 This->stencilBufferTarget = pNewZStencil;
7084 /* should we be calling the parent or the wined3d surface? */
7085 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7086 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7087 hr = WINED3D_OK;
7088 /** TODO: glEnable/glDisable on depth/stencil depending on
7089 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7090 **********************************************************/
7093 return hr;
7097 #ifdef GL_VERSION_1_3
7098 /* Internal functions not in DirectX */
7099 /** TODO: move this off to the opengl context manager
7100 *(the swapchain doesn't need to know anything about offscreen rendering!)
7101 ****************************************************/
7103 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7107 TRACE("(%p), %p\n", This, swapchain);
7109 if (swapchain->win != swapchain->drawable) {
7110 /* Set everything back the way it ws */
7111 swapchain->render_ctx = swapchain->glCtx;
7112 swapchain->drawable = swapchain->win;
7114 return WINED3D_OK;
7117 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7118 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7120 int i;
7121 unsigned int width;
7122 unsigned int height;
7123 WINED3DFORMAT format;
7124 WINED3DSURFACE_DESC surfaceDesc;
7125 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7126 surfaceDesc.Width = &width;
7127 surfaceDesc.Height = &height;
7128 surfaceDesc.Format = &format;
7129 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7130 *context = NULL;
7131 /* I need a get width/height function (and should do something with the format) */
7132 for (i = 0; i < CONTEXT_CACHE; ++i) {
7133 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7134 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7135 the pSurface can be set to 0 allowing it to be reused from cache **/
7136 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7137 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7138 *context = &This->contextCache[i];
7139 break;
7141 if (This->contextCache[i].Width == 0) {
7142 This->contextCache[i].pSurface = pSurface;
7143 This->contextCache[i].Width = width;
7144 This->contextCache[i].Height = height;
7145 *context = &This->contextCache[i];
7146 break;
7149 if (i == CONTEXT_CACHE) {
7150 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7151 glContext *dropContext = 0;
7152 for (i = 0; i < CONTEXT_CACHE; i++) {
7153 if (This->contextCache[i].usedcount < minUsage) {
7154 dropContext = &This->contextCache[i];
7155 minUsage = This->contextCache[i].usedcount;
7158 /* clean up the context (this doesn't work for ATI at the moment */
7159 #if 0
7160 glXDestroyContext(swapchain->display, dropContext->context);
7161 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7162 #endif
7163 FIXME("Leak\n");
7164 dropContext->Width = 0;
7165 dropContext->pSurface = pSurface;
7166 *context = dropContext;
7167 } else {
7168 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7169 for (i = 0; i < CONTEXT_CACHE; i++) {
7170 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7174 if (*context != NULL)
7175 return WINED3D_OK;
7176 else
7177 return E_OUTOFMEMORY;
7179 #endif
7181 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7182 * the functionality needs splitting up so that we don't do more than we should do.
7183 * this only seems to impact performance a little.
7184 ******************************/
7185 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7186 IWineD3DSurface *RenderSurface) {
7187 HRESULT ret = WINED3DERR_INVALIDCALL;
7188 BOOL oldRecording;
7189 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7192 * Currently only active for GLX >= 1.3
7193 * for others versions we'll have to use GLXPixmaps
7195 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7196 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7197 * so only check OpenGL version
7198 * ..........................
7199 * I don't believe that it is a problem with NVidia headers,
7200 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7201 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7202 * ATI Note:
7203 * Your application will report GLX version 1.2 on glXQueryVersion.
7204 * However, it is safe to call the GLX 1.3 functions as described below.
7206 #if defined(GL_VERSION_1_3)
7208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7209 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7210 IWineD3DSurface *tmp;
7211 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7212 GLXFBConfig* cfgs = NULL;
7213 int nCfgs = 0;
7214 int attribs[256];
7215 int nAttribs = 0;
7216 IWineD3DSwapChain *currentSwapchain;
7217 IWineD3DSwapChainImpl *swapchain;
7218 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7219 * but switch them off if the StencilSurface is set to NULL
7220 ** *********************************************************/
7221 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7222 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7224 /**TODO:
7225 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7226 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7229 #define PUSH1(att) attribs[nAttribs++] = (att);
7230 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7232 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7234 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7235 IWineD3DSwapChainImpl *impSwapChain;
7236 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7237 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7238 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7241 ENTER_GL();
7243 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7244 PUSH2(GLX_X_RENDERABLE, TRUE);
7245 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7246 TRACE("calling makeglcfg\n");
7247 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7248 PUSH1(None);
7250 TRACE("calling chooseFGConfig\n");
7251 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7252 attribs, &nCfgs);
7254 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7255 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7256 why we failed and only show this message once! */
7257 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"); /**/
7258 nAttribs = 0;
7259 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7260 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7261 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7262 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7263 TRACE("calling makeglcfg\n");
7264 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7265 PUSH1(None);
7266 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7267 attribs, &nCfgs);
7270 if (NULL != cfgs) {
7271 #ifdef EXTRA_TRACES
7272 int i;
7273 for (i = 0; i < nCfgs; ++i) {
7274 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7275 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7276 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7279 if (NULL != This->renderTarget) {
7280 glFlush();
7281 vcheckGLcall("glFlush");
7282 /** This is only useful if the old render target was a swapchain,
7283 * we need to supercede this with a function that displays
7284 * the current buffer on the screen. This is easy to do in glx1.3 but
7285 * we need to do copy-write pixels in glx 1.2.
7286 ************************************************/
7287 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7289 printf("Hit Enter to get next frame ...\n");
7290 getchar();
7292 #endif
7295 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7296 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7297 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7301 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7302 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7303 **********************************************************************/
7304 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7305 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7306 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7307 TRACE("making swapchain active\n");
7308 if (RenderSurface != This->renderTarget) {
7309 BOOL backbuf = FALSE;
7310 int i;
7312 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7313 if(RenderSurface == swapchain->backBuffer[i]) {
7314 backbuf = TRUE;
7315 break;
7319 if (backbuf) {
7320 } else {
7321 /* This could be flagged so that some operations work directly with the front buffer */
7322 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7324 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7325 == False) {
7326 TRACE("Error in setting current context: context %p drawable %ld !\n",
7327 impSwapChain->glCtx, impSwapChain->win);
7330 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7332 checkGLcall("glXMakeContextCurrent");
7334 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7336 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7338 /** ********************************************************************
7339 * This is a quickly hacked out implementation of offscreen textures.
7340 * It will work in most cases but there may be problems if the client
7341 * modifies the texture directly, or expects the contents of the rendertarget
7342 * to be persistent.
7344 * There are some real speed vs compatibility issues here:
7345 * we should really use a new context for every texture, but that eats ram.
7346 * we should also be restoring the texture to the pbuffer but that eats CPU
7347 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7348 * but if this means reusing the display backbuffer then we need to make sure that
7349 * states are correctly preserved.
7350 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7351 * and gain a good performance increase at the cost of compatibility.
7352 * I would suggest that, when this is the case, a user configurable flag be made
7353 * available, allowing the user to choose the best emulated experience for them.
7354 *********************************************************************/
7356 XVisualInfo *visinfo;
7357 glContext *newContext;
7359 /* Here were using a shared context model */
7360 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7361 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7364 /* If the context doesn't exist then create a new one */
7365 /* TODO: This should really be part of findGlContext */
7366 if (NULL == newContext->context) {
7368 TRACE("making new buffer\n");
7369 nAttribs = 0;
7370 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7371 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7372 PUSH1(None);
7374 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7376 /** ****************************************
7377 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7378 *they note:
7379 * In future releases, we may provide the calls glXCreateNewContext,
7380 * glXQueryDrawable and glXMakeContextCurrent.
7381 * so until then we have to use glXGetVisualFromFBConfig &co..
7382 ********************************************/
7385 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7386 if (!visinfo) {
7387 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7388 } else {
7389 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7390 XFree(visinfo);
7393 if (NULL == newContext || NULL == newContext->context) {
7394 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7395 } else {
7396 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7397 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7398 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7401 /* Clean up the old context */
7402 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7403 /* Set the current context of the swapchain to the new context */
7404 impSwapChain->drawable = newContext->drawable;
7405 impSwapChain->render_ctx = newContext->context;
7409 /* Disable recording, and apply the stateblock to the new context
7410 * FIXME: This is a bit of a hack, each context should know it's own state,
7411 * the directX current directX state should then be applied to the context */
7412 oldUpdateStateBlock = This->updateStateBlock;
7413 oldRecording= This->isRecordingState;
7414 This->isRecordingState = FALSE;
7415 This->updateStateBlock = This->stateBlock;
7416 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7418 /* clean up the current rendertargets swapchain (if it belonged to one) */
7419 if (currentSwapchain != NULL) {
7420 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7423 /* Were done with the opengl context management, setup the rendertargets */
7425 tmp = This->renderTarget;
7426 This->renderTarget = RenderSurface;
7427 IWineD3DSurface_AddRef(This->renderTarget);
7428 IWineD3DSurface_Release(tmp);
7431 DWORD value;
7433 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7434 /* Check that the container is not a swapchain member */
7436 IWineD3DSwapChain *tmpSwapChain;
7437 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7438 This->renderUpsideDown = TRUE;
7439 }else{
7440 This->renderUpsideDown = FALSE;
7441 IWineD3DSwapChain_Release(tmpSwapChain);
7443 /* Force updating the cull mode */
7444 TRACE("setting render state\n");
7445 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7446 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7448 /* Force updating projection matrix */
7449 This->last_was_rhw = FALSE;
7450 This->proj_valid = FALSE;
7453 /* Restore recording state */
7454 This->isRecordingState = oldRecording;
7455 This->updateStateBlock = oldUpdateStateBlock;
7457 ret = WINED3D_OK;
7459 if (cfgs != NULL) {
7460 XFree(cfgs);
7461 } else {
7462 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7463 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7466 #undef PUSH1
7467 #undef PUSH2
7468 if ( NULL != impSwapChain) {
7469 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7471 LEAVE_GL();
7473 #endif
7474 return ret;
7477 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7478 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7480 /* TODO: the use of Impl is deprecated. */
7481 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7483 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7485 /* some basic validation checks */
7486 if(This->cursorTexture) {
7487 ENTER_GL();
7488 glDeleteTextures(1, &This->cursorTexture);
7489 LEAVE_GL();
7490 This->cursorTexture = 0;
7493 if(pCursorBitmap) {
7494 /* MSDN: Cursor must be A8R8G8B8 */
7495 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7496 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7497 return WINED3DERR_INVALIDCALL;
7500 /* MSDN: Cursor must be smaller than the display mode */
7501 if(pSur->currentDesc.Width > This->ddraw_width ||
7502 pSur->currentDesc.Height > This->ddraw_height) {
7503 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %ldx%ld\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7504 return WINED3DERR_INVALIDCALL;
7507 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7508 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7509 * Texture and Blitting code to draw the cursor
7511 pSur->Flags |= SFLAG_FORCELOAD;
7512 IWineD3DSurface_PreLoad(pCursorBitmap);
7513 pSur->Flags &= ~SFLAG_FORCELOAD;
7514 /* Do not store the surface's pointer because the application may release
7515 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7516 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7518 This->cursorTexture = pSur->glDescription.textureName;
7519 This->cursorWidth = pSur->currentDesc.Width;
7520 This->cursorHeight = pSur->currentDesc.Height;
7521 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7524 This->xHotSpot = XHotSpot;
7525 This->yHotSpot = YHotSpot;
7526 return WINED3D_OK;
7529 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7531 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7533 This->xScreenSpace = XScreenSpace;
7534 This->yScreenSpace = YScreenSpace;
7536 return;
7540 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7542 TRACE("(%p) : visible(%d)\n", This, bShow);
7544 This->bCursorVisible = bShow;
7546 return WINED3D_OK;
7549 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7551 TRACE("(%p) : state (%lu)\n", This, This->state);
7552 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7553 switch (This->state) {
7554 case WINED3D_OK:
7555 return WINED3D_OK;
7556 case WINED3DERR_DEVICELOST:
7558 ResourceList *resourceList = This->resources;
7559 while (NULL != resourceList) {
7560 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7561 return WINED3DERR_DEVICENOTRESET;
7562 resourceList = resourceList->next;
7564 return WINED3DERR_DEVICELOST;
7566 case WINED3DERR_DRIVERINTERNALERROR:
7567 return WINED3DERR_DRIVERINTERNALERROR;
7570 /* Unknown state */
7571 return WINED3DERR_DRIVERINTERNALERROR;
7575 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7577 /** FIXME: Resource tracking needs to be done,
7578 * The closes we can do to this is set the priorities of all managed textures low
7579 * and then reset them.
7580 ***********************************************************/
7581 FIXME("(%p) : stub\n", This);
7582 return WINED3D_OK;
7585 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7587 /** FIXME: Resource trascking needs to be done.
7588 * in effect this pulls all non only default
7589 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7590 * and should clear down the context and set it up according to pPresentationParameters
7591 ***********************************************************/
7592 FIXME("(%p) : stub\n", This);
7593 return WINED3D_OK;
7596 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7598 /** FIXME: always true at the moment **/
7599 if(bEnableDialogs == FALSE) {
7600 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7602 return WINED3D_OK;
7606 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7608 TRACE("(%p) : pParameters %p\n", This, pParameters);
7610 *pParameters = This->createParms;
7611 return WINED3D_OK;
7614 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7615 IWineD3DSwapChain *swapchain;
7616 HRESULT hrc = WINED3D_OK;
7618 TRACE("Relaying to swapchain\n");
7620 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7621 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7622 IWineD3DSwapChain_Release(swapchain);
7624 return;
7627 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7628 IWineD3DSwapChain *swapchain;
7629 HRESULT hrc = WINED3D_OK;
7631 TRACE("Relaying to swapchain\n");
7633 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7634 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7635 IWineD3DSwapChain_Release(swapchain);
7637 return;
7641 /** ********************************************************
7642 * Notification functions
7643 ** ********************************************************/
7644 /** This function must be called in the release of a resource when ref == 0,
7645 * the contents of resource must still be correct,
7646 * any handels to other resource held by the caller must be closed
7647 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7648 *****************************************************/
7649 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7651 ResourceList* resourceList;
7653 TRACE("(%p) : resource %p\n", This, resource);
7654 #if 0
7655 EnterCriticalSection(&resourceStoreCriticalSection);
7656 #endif
7657 /* add a new texture to the frot of the linked list */
7658 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7659 resourceList->resource = resource;
7661 /* Get the old head */
7662 resourceList->next = This->resources;
7664 This->resources = resourceList;
7665 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7667 #if 0
7668 LeaveCriticalSection(&resourceStoreCriticalSection);
7669 #endif
7670 return;
7673 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7675 ResourceList* resourceList = NULL;
7676 ResourceList* previousResourceList = NULL;
7678 TRACE("(%p) : resource %p\n", This, resource);
7680 #if 0
7681 EnterCriticalSection(&resourceStoreCriticalSection);
7682 #endif
7683 resourceList = This->resources;
7685 while (resourceList != NULL) {
7686 if(resourceList->resource == resource) break;
7687 previousResourceList = resourceList;
7688 resourceList = resourceList->next;
7691 if (resourceList == NULL) {
7692 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7693 #if 0
7694 LeaveCriticalSection(&resourceStoreCriticalSection);
7695 #endif
7696 return;
7697 } else {
7698 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7700 /* make sure we don't leave a hole in the list */
7701 if (previousResourceList != NULL) {
7702 previousResourceList->next = resourceList->next;
7703 } else {
7704 This->resources = resourceList->next;
7707 #if 0
7708 LeaveCriticalSection(&resourceStoreCriticalSection);
7709 #endif
7710 return;
7714 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7716 int counter;
7718 TRACE("(%p) : resource %p\n", This, resource);
7719 switch(IWineD3DResource_GetType(resource)){
7720 case WINED3DRTYPE_SURFACE:
7721 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7722 break;
7723 case WINED3DRTYPE_TEXTURE:
7724 case WINED3DRTYPE_CUBETEXTURE:
7725 case WINED3DRTYPE_VOLUMETEXTURE:
7726 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7727 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7728 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7729 This->stateBlock->textures[counter] = NULL;
7731 if (This->updateStateBlock != This->stateBlock ){
7732 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7733 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7734 This->updateStateBlock->textures[counter] = NULL;
7738 break;
7739 case WINED3DRTYPE_VOLUME:
7740 /* TODO: nothing really? */
7741 break;
7742 case WINED3DRTYPE_VERTEXBUFFER:
7743 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7745 int streamNumber;
7746 TRACE("Cleaning up stream pointers\n");
7748 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7749 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7750 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7752 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7753 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7754 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7755 This->updateStateBlock->streamSource[streamNumber] = 0;
7756 /* Set changed flag? */
7759 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) */
7760 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7761 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7762 This->stateBlock->streamSource[streamNumber] = 0;
7765 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7766 else { /* This shouldn't happen */
7767 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7769 #endif
7773 break;
7774 case WINED3DRTYPE_INDEXBUFFER:
7775 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7776 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7777 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7778 This->updateStateBlock->pIndexData = NULL;
7781 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7782 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7783 This->stateBlock->pIndexData = NULL;
7787 break;
7788 default:
7789 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7790 break;
7794 /* Remove the resoruce from the resourceStore */
7795 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7797 TRACE("Resource released\n");
7801 /**********************************************************
7802 * IWineD3DDevice VTbl follows
7803 **********************************************************/
7805 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7807 /*** IUnknown methods ***/
7808 IWineD3DDeviceImpl_QueryInterface,
7809 IWineD3DDeviceImpl_AddRef,
7810 IWineD3DDeviceImpl_Release,
7811 /*** IWineD3DDevice methods ***/
7812 IWineD3DDeviceImpl_GetParent,
7813 /*** Creation methods**/
7814 IWineD3DDeviceImpl_CreateVertexBuffer,
7815 IWineD3DDeviceImpl_CreateIndexBuffer,
7816 IWineD3DDeviceImpl_CreateStateBlock,
7817 IWineD3DDeviceImpl_CreateSurface,
7818 IWineD3DDeviceImpl_CreateTexture,
7819 IWineD3DDeviceImpl_CreateVolumeTexture,
7820 IWineD3DDeviceImpl_CreateVolume,
7821 IWineD3DDeviceImpl_CreateCubeTexture,
7822 IWineD3DDeviceImpl_CreateQuery,
7823 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7824 IWineD3DDeviceImpl_CreateVertexDeclaration,
7825 IWineD3DDeviceImpl_CreateVertexShader,
7826 IWineD3DDeviceImpl_CreatePixelShader,
7827 IWineD3DDeviceImpl_CreatePalette,
7828 /*** Odd functions **/
7829 IWineD3DDeviceImpl_Init3D,
7830 IWineD3DDeviceImpl_Uninit3D,
7831 IWineD3DDeviceImpl_EnumDisplayModes,
7832 IWineD3DDeviceImpl_EvictManagedResources,
7833 IWineD3DDeviceImpl_GetAvailableTextureMem,
7834 IWineD3DDeviceImpl_GetBackBuffer,
7835 IWineD3DDeviceImpl_GetCreationParameters,
7836 IWineD3DDeviceImpl_GetDeviceCaps,
7837 IWineD3DDeviceImpl_GetDirect3D,
7838 IWineD3DDeviceImpl_GetDisplayMode,
7839 IWineD3DDeviceImpl_SetDisplayMode,
7840 IWineD3DDeviceImpl_GetHWND,
7841 IWineD3DDeviceImpl_SetHWND,
7842 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7843 IWineD3DDeviceImpl_GetRasterStatus,
7844 IWineD3DDeviceImpl_GetSwapChain,
7845 IWineD3DDeviceImpl_Reset,
7846 IWineD3DDeviceImpl_SetDialogBoxMode,
7847 IWineD3DDeviceImpl_SetCursorProperties,
7848 IWineD3DDeviceImpl_SetCursorPosition,
7849 IWineD3DDeviceImpl_ShowCursor,
7850 IWineD3DDeviceImpl_TestCooperativeLevel,
7851 /*** Getters and setters **/
7852 IWineD3DDeviceImpl_SetClipPlane,
7853 IWineD3DDeviceImpl_GetClipPlane,
7854 IWineD3DDeviceImpl_SetClipStatus,
7855 IWineD3DDeviceImpl_GetClipStatus,
7856 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7857 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7858 IWineD3DDeviceImpl_SetDepthStencilSurface,
7859 IWineD3DDeviceImpl_GetDepthStencilSurface,
7860 IWineD3DDeviceImpl_SetFVF,
7861 IWineD3DDeviceImpl_GetFVF,
7862 IWineD3DDeviceImpl_SetGammaRamp,
7863 IWineD3DDeviceImpl_GetGammaRamp,
7864 IWineD3DDeviceImpl_SetIndices,
7865 IWineD3DDeviceImpl_GetIndices,
7866 IWineD3DDeviceImpl_SetLight,
7867 IWineD3DDeviceImpl_GetLight,
7868 IWineD3DDeviceImpl_SetLightEnable,
7869 IWineD3DDeviceImpl_GetLightEnable,
7870 IWineD3DDeviceImpl_SetMaterial,
7871 IWineD3DDeviceImpl_GetMaterial,
7872 IWineD3DDeviceImpl_SetNPatchMode,
7873 IWineD3DDeviceImpl_GetNPatchMode,
7874 IWineD3DDeviceImpl_SetPaletteEntries,
7875 IWineD3DDeviceImpl_GetPaletteEntries,
7876 IWineD3DDeviceImpl_SetPixelShader,
7877 IWineD3DDeviceImpl_GetPixelShader,
7878 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7879 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7880 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7881 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7882 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7883 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7884 IWineD3DDeviceImpl_SetRenderState,
7885 IWineD3DDeviceImpl_GetRenderState,
7886 IWineD3DDeviceImpl_SetRenderTarget,
7887 IWineD3DDeviceImpl_GetRenderTarget,
7888 IWineD3DDeviceImpl_SetFrontBackBuffers,
7889 IWineD3DDeviceImpl_SetSamplerState,
7890 IWineD3DDeviceImpl_GetSamplerState,
7891 IWineD3DDeviceImpl_SetScissorRect,
7892 IWineD3DDeviceImpl_GetScissorRect,
7893 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7894 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7895 IWineD3DDeviceImpl_SetStreamSource,
7896 IWineD3DDeviceImpl_GetStreamSource,
7897 IWineD3DDeviceImpl_SetStreamSourceFreq,
7898 IWineD3DDeviceImpl_GetStreamSourceFreq,
7899 IWineD3DDeviceImpl_SetTexture,
7900 IWineD3DDeviceImpl_GetTexture,
7901 IWineD3DDeviceImpl_SetTextureStageState,
7902 IWineD3DDeviceImpl_GetTextureStageState,
7903 IWineD3DDeviceImpl_SetTransform,
7904 IWineD3DDeviceImpl_GetTransform,
7905 IWineD3DDeviceImpl_SetVertexDeclaration,
7906 IWineD3DDeviceImpl_GetVertexDeclaration,
7907 IWineD3DDeviceImpl_SetVertexShader,
7908 IWineD3DDeviceImpl_GetVertexShader,
7909 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7910 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7911 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7912 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7913 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7914 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7915 IWineD3DDeviceImpl_SetViewport,
7916 IWineD3DDeviceImpl_GetViewport,
7917 IWineD3DDeviceImpl_MultiplyTransform,
7918 IWineD3DDeviceImpl_ValidateDevice,
7919 IWineD3DDeviceImpl_ProcessVertices,
7920 /*** State block ***/
7921 IWineD3DDeviceImpl_BeginStateBlock,
7922 IWineD3DDeviceImpl_EndStateBlock,
7923 /*** Scene management ***/
7924 IWineD3DDeviceImpl_BeginScene,
7925 IWineD3DDeviceImpl_EndScene,
7926 IWineD3DDeviceImpl_Present,
7927 IWineD3DDeviceImpl_Clear,
7928 /*** Drawing ***/
7929 IWineD3DDeviceImpl_DrawPrimitive,
7930 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7931 IWineD3DDeviceImpl_DrawPrimitiveUP,
7932 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7933 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7934 IWineD3DDeviceImpl_DrawRectPatch,
7935 IWineD3DDeviceImpl_DrawTriPatch,
7936 IWineD3DDeviceImpl_DeletePatch,
7937 IWineD3DDeviceImpl_ColorFill,
7938 IWineD3DDeviceImpl_UpdateTexture,
7939 IWineD3DDeviceImpl_UpdateSurface,
7940 IWineD3DDeviceImpl_CopyRects,
7941 IWineD3DDeviceImpl_StretchRect,
7942 IWineD3DDeviceImpl_GetRenderTargetData,
7943 IWineD3DDeviceImpl_GetFrontBufferData,
7944 /*** Internal use IWineD3DDevice methods ***/
7945 IWineD3DDeviceImpl_SetupTextureStates,
7946 /*** object tracking ***/
7947 IWineD3DDeviceImpl_ResourceReleased
7951 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7952 WINED3DRS_ALPHABLENDENABLE ,
7953 WINED3DRS_ALPHAFUNC ,
7954 WINED3DRS_ALPHAREF ,
7955 WINED3DRS_ALPHATESTENABLE ,
7956 WINED3DRS_BLENDOP ,
7957 WINED3DRS_COLORWRITEENABLE ,
7958 WINED3DRS_DESTBLEND ,
7959 WINED3DRS_DITHERENABLE ,
7960 WINED3DRS_FILLMODE ,
7961 WINED3DRS_FOGDENSITY ,
7962 WINED3DRS_FOGEND ,
7963 WINED3DRS_FOGSTART ,
7964 WINED3DRS_LASTPIXEL ,
7965 WINED3DRS_SHADEMODE ,
7966 WINED3DRS_SRCBLEND ,
7967 WINED3DRS_STENCILENABLE ,
7968 WINED3DRS_STENCILFAIL ,
7969 WINED3DRS_STENCILFUNC ,
7970 WINED3DRS_STENCILMASK ,
7971 WINED3DRS_STENCILPASS ,
7972 WINED3DRS_STENCILREF ,
7973 WINED3DRS_STENCILWRITEMASK ,
7974 WINED3DRS_STENCILZFAIL ,
7975 WINED3DRS_TEXTUREFACTOR ,
7976 WINED3DRS_WRAP0 ,
7977 WINED3DRS_WRAP1 ,
7978 WINED3DRS_WRAP2 ,
7979 WINED3DRS_WRAP3 ,
7980 WINED3DRS_WRAP4 ,
7981 WINED3DRS_WRAP5 ,
7982 WINED3DRS_WRAP6 ,
7983 WINED3DRS_WRAP7 ,
7984 WINED3DRS_ZENABLE ,
7985 WINED3DRS_ZFUNC ,
7986 WINED3DRS_ZWRITEENABLE
7989 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7990 WINED3DTSS_ADDRESSW ,
7991 WINED3DTSS_ALPHAARG0 ,
7992 WINED3DTSS_ALPHAARG1 ,
7993 WINED3DTSS_ALPHAARG2 ,
7994 WINED3DTSS_ALPHAOP ,
7995 WINED3DTSS_BUMPENVLOFFSET ,
7996 WINED3DTSS_BUMPENVLSCALE ,
7997 WINED3DTSS_BUMPENVMAT00 ,
7998 WINED3DTSS_BUMPENVMAT01 ,
7999 WINED3DTSS_BUMPENVMAT10 ,
8000 WINED3DTSS_BUMPENVMAT11 ,
8001 WINED3DTSS_COLORARG0 ,
8002 WINED3DTSS_COLORARG1 ,
8003 WINED3DTSS_COLORARG2 ,
8004 WINED3DTSS_COLOROP ,
8005 WINED3DTSS_RESULTARG ,
8006 WINED3DTSS_TEXCOORDINDEX ,
8007 WINED3DTSS_TEXTURETRANSFORMFLAGS
8010 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8011 WINED3DSAMP_ADDRESSU ,
8012 WINED3DSAMP_ADDRESSV ,
8013 WINED3DSAMP_ADDRESSW ,
8014 WINED3DSAMP_BORDERCOLOR ,
8015 WINED3DSAMP_MAGFILTER ,
8016 WINED3DSAMP_MINFILTER ,
8017 WINED3DSAMP_MIPFILTER ,
8018 WINED3DSAMP_MIPMAPLODBIAS ,
8019 WINED3DSAMP_MAXMIPLEVEL ,
8020 WINED3DSAMP_MAXANISOTROPY ,
8021 WINED3DSAMP_SRGBTEXTURE ,
8022 WINED3DSAMP_ELEMENTINDEX
8025 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8026 WINED3DRS_AMBIENT ,
8027 WINED3DRS_AMBIENTMATERIALSOURCE ,
8028 WINED3DRS_CLIPPING ,
8029 WINED3DRS_CLIPPLANEENABLE ,
8030 WINED3DRS_COLORVERTEX ,
8031 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8032 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8033 WINED3DRS_FOGDENSITY ,
8034 WINED3DRS_FOGEND ,
8035 WINED3DRS_FOGSTART ,
8036 WINED3DRS_FOGTABLEMODE ,
8037 WINED3DRS_FOGVERTEXMODE ,
8038 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8039 WINED3DRS_LIGHTING ,
8040 WINED3DRS_LOCALVIEWER ,
8041 WINED3DRS_MULTISAMPLEANTIALIAS ,
8042 WINED3DRS_MULTISAMPLEMASK ,
8043 WINED3DRS_NORMALIZENORMALS ,
8044 WINED3DRS_PATCHEDGESTYLE ,
8045 WINED3DRS_POINTSCALE_A ,
8046 WINED3DRS_POINTSCALE_B ,
8047 WINED3DRS_POINTSCALE_C ,
8048 WINED3DRS_POINTSCALEENABLE ,
8049 WINED3DRS_POINTSIZE ,
8050 WINED3DRS_POINTSIZE_MAX ,
8051 WINED3DRS_POINTSIZE_MIN ,
8052 WINED3DRS_POINTSPRITEENABLE ,
8053 WINED3DRS_RANGEFOGENABLE ,
8054 WINED3DRS_SPECULARMATERIALSOURCE ,
8055 WINED3DRS_TWEENFACTOR ,
8056 WINED3DRS_VERTEXBLEND
8059 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8060 WINED3DTSS_TEXCOORDINDEX ,
8061 WINED3DTSS_TEXTURETRANSFORMFLAGS
8064 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8065 WINED3DSAMP_DMAPOFFSET