wined3d: Do not use the IWineD3DSurface for the cursor.
[wine.git] / dlls / wined3d / device.c
blob651d1349bc3920a6c512060f83d2fca60bc5d336
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\n", object);
621 ENTER_GL();
622 /* Make sure that the gl error is cleared. Do not use checkGLcall
623 * here because checkGLcall just prints a fixme and continues. However,
624 * if an error during VBO creation occurs we can fall back to non-vbo operation
625 * with full functionality(but performance loss)
627 while(glGetError() != GL_NO_ERROR);
629 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
630 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
631 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
632 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
633 * to check if the rhw and color values are in the correct format.
636 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
637 error = glGetError();
638 if(object->vbo == 0 || error != GL_NO_ERROR) {
639 WARN("Failed to create a VBO with error %d\n", error);
640 goto error;
643 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
644 error = glGetError();
645 if(error != GL_NO_ERROR) {
646 WARN("Failed to bind the VBO, error %d\n", error);
647 goto error;
650 /* Transformed vertices are horribly inflexible. If the app specifies an
651 * vertex buffer with transformed vertices in default pool without DYNAMIC
652 * usage assume DYNAMIC usage and print a warning. The app will have to update
653 * the vertices regularily for them to be useful
655 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
656 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
657 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
658 vboUsage |= WINED3DUSAGE_DYNAMIC;
661 /* Don't use static, because dx apps tend to update the buffer
662 * quite often even if they specify 0 usage
664 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
665 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
666 TRACE("Gl usage = GL_STREAM_DRAW\n");
667 glUsage = GL_STREAM_DRAW_ARB;
668 break;
669 case D3DUSAGE_WRITEONLY:
670 TRACE("Gl usage = GL_STATIC_DRAW\n");
671 glUsage = GL_DYNAMIC_DRAW_ARB;
672 break;
673 case D3DUSAGE_DYNAMIC:
674 TRACE("Gl usage = GL_STREAM_COPY\n");
675 glUsage = GL_STREAM_COPY_ARB;
676 break;
677 default:
678 TRACE("Gl usage = GL_STATIC_COPY\n");
679 glUsage = GL_DYNAMIC_COPY_ARB;
680 break;
683 /* Reserve memory for the buffer. The amount of data won't change
684 * so we are safe with calling glBufferData once with a NULL ptr and
685 * calling glBufferSubData on updates
687 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
688 error = glGetError();
689 if(error != GL_NO_ERROR) {
690 WARN("glBufferDataARB failed with error %d\n", error);
691 goto error;
694 LEAVE_GL();
696 return;
697 error:
698 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
699 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
700 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
701 object->vbo = 0;
702 object->Flags |= VBFLAG_VBOCREATEFAIL;
703 LEAVE_GL();
704 return;
707 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
708 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
709 IUnknown *parent) {
710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
711 IWineD3DVertexBufferImpl *object;
712 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
713 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
714 BOOL conv;
715 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
717 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
718 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
720 if(Size == 0) return WINED3DERR_INVALIDCALL;
722 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
723 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
725 object->fvf = FVF;
727 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
728 * drawStridedFast (half-life 2).
730 * Basically converting the vertices in the buffer is quite expensive, and observations
731 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
732 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
734 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
735 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
736 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
737 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
738 * dx7 apps.
739 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
740 * more. In this call we can convert dx7 buffers too.
742 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
743 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
744 (dxVersion > 7 || !conv) ) {
745 CreateVBO(object);
747 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
748 if(dxVersion == 7 && object->vbo) {
749 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
750 object->resource.allocatedMemory = NULL;
754 return WINED3D_OK;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
758 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
759 HANDLE *sharedHandle, IUnknown *parent) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DIndexBufferImpl *object;
762 TRACE("(%p) Creating index buffer\n", This);
764 /* Allocate the storage for the device */
765 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
767 /*TODO: use VBO's */
768 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
769 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
772 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
773 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
774 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
776 return WINED3D_OK;
779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DStateBlockImpl *object;
783 int i, j;
784 HRESULT temp_result;
786 D3DCREATEOBJECTINSTANCE(object, StateBlock)
787 object->blockType = Type;
789 /* Special case - Used during initialization to produce a placeholder stateblock
790 so other functions called can update a state block */
791 if (Type == WINED3DSBT_INIT) {
792 /* Don't bother increasing the reference count otherwise a device will never
793 be freed due to circular dependencies */
794 return WINED3D_OK;
797 temp_result = allocate_shader_constants(object);
798 if (WINED3D_OK != temp_result)
799 return temp_result;
801 /* Otherwise, might as well set the whole state block to the appropriate values */
802 if (This->stateBlock != NULL)
803 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
804 else
805 memset(object->streamFreq, 1, sizeof(object->streamFreq));
807 /* Reset the ref and type after kludging it */
808 object->wineD3DDevice = This;
809 object->ref = 1;
810 object->blockType = Type;
812 TRACE("Updating changed flags appropriate for type %d\n", Type);
814 if (Type == WINED3DSBT_ALL) {
816 TRACE("ALL => Pretend everything has changed\n");
817 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
819 } else if (Type == WINED3DSBT_PIXELSTATE) {
821 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
822 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
824 object->changed.pixelShader = TRUE;
826 /* Pixel Shader Constants */
827 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
828 object->changed.pixelShaderConstantsF[i] = TRUE;
829 for (i = 0; i < MAX_CONST_B; ++i)
830 object->changed.pixelShaderConstantsB[i] = TRUE;
831 for (i = 0; i < MAX_CONST_I; ++i)
832 object->changed.pixelShaderConstantsI[i] = TRUE;
834 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
835 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
837 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
838 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
839 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
842 for (j = 0 ; j < 16; j++) {
843 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
845 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
849 } else if (Type == WINED3DSBT_VERTEXSTATE) {
851 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
852 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
854 object->changed.vertexShader = TRUE;
856 /* Vertex Shader Constants */
857 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
858 object->changed.vertexShaderConstantsF[i] = TRUE;
859 for (i = 0; i < MAX_CONST_B; ++i)
860 object->changed.vertexShaderConstantsB[i] = TRUE;
861 for (i = 0; i < MAX_CONST_I; ++i)
862 object->changed.vertexShaderConstantsI[i] = TRUE;
864 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
865 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
867 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
868 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
869 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
872 for (j = 0 ; j < 16; j++){
873 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
874 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
878 /* Duplicate light chain */
880 PLIGHTINFOEL *src = NULL;
881 PLIGHTINFOEL *dst = NULL;
882 PLIGHTINFOEL *newEl = NULL;
883 src = This->stateBlock->lights;
884 object->lights = NULL;
887 while (src) {
888 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
889 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
890 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
891 newEl->prev = dst;
892 newEl->changed = TRUE;
893 newEl->enabledChanged = TRUE;
894 if (dst == NULL) {
895 object->lights = newEl;
896 } else {
897 dst->next = newEl;
899 dst = newEl;
900 src = src->next;
905 } else {
906 FIXME("Unrecognized state block type %d\n", Type);
909 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
910 return WINED3D_OK;
914 /* ************************************
915 MSDN:
916 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
918 Discard
919 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
921 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
923 ******************************** */
925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
928 unsigned int pow2Width, pow2Height;
929 unsigned int Size = 1;
930 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
931 TRACE("(%p) Create surface\n",This);
933 /** FIXME: Check ranges on the inputs are valid
934 * MSDN
935 * MultisampleQuality
936 * [in] Quality level. The valid range is between zero and one less than the level
937 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
938 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
939 * values of paired render targets, depth stencil surfaces, and the MultiSample type
940 * must all match.
941 *******************************/
945 * TODO: Discard MSDN
946 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
948 * If this flag is set, the contents of the depth stencil buffer will be
949 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
950 * with a different depth surface.
952 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
953 ***************************/
955 if(MultisampleQuality < 0) {
956 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
957 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
960 if(MultisampleQuality > 0) {
961 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
962 MultisampleQuality=0;
965 /** FIXME: Check that the format is supported
966 * by the device.
967 *******************************/
969 /* Non-power2 support */
971 /* Find the nearest pow2 match */
972 pow2Width = pow2Height = 1;
973 while (pow2Width < Width) pow2Width <<= 1;
974 while (pow2Height < Height) pow2Height <<= 1;
976 if (pow2Width > Width || pow2Height > Height) {
977 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
978 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
979 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
980 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
981 This, Width, Height);
982 return WINED3DERR_NOTAVAILABLE;
986 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
987 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
988 * space!
989 *********************************/
990 if (WINED3DFMT_UNKNOWN == Format) {
991 Size = 0;
992 } else if (Format == WINED3DFMT_DXT1) {
993 /* DXT1 is half byte per pixel */
994 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
996 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
997 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
998 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
999 } else {
1000 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1003 /** Create and initialise the surface resource **/
1004 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1005 /* "Standalone" surface */
1006 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1008 object->currentDesc.Width = Width;
1009 object->currentDesc.Height = Height;
1010 object->currentDesc.MultiSampleType = MultiSample;
1011 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1013 /* Setup some glformat defaults */
1014 object->glDescription.glFormat = tableEntry->glFormat;
1015 object->glDescription.glFormatInternal = tableEntry->glInternal;
1016 object->glDescription.glType = tableEntry->glType;
1018 object->glDescription.textureName = 0;
1019 object->glDescription.level = Level;
1020 object->glDescription.target = GL_TEXTURE_2D;
1022 /* Internal data */
1023 object->pow2Width = pow2Width;
1024 object->pow2Height = pow2Height;
1026 /* Flags */
1027 object->Flags = 0; /* We start without flags set */
1028 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1029 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1030 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1031 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1034 if (WINED3DFMT_UNKNOWN != Format) {
1035 object->bytesPerPixel = tableEntry->bpp;
1036 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1037 } else {
1038 object->bytesPerPixel = 0;
1039 object->pow2Size = 0;
1042 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1044 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1046 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1047 * this function is too deap to need to care about things like this.
1048 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1049 * ****************************************/
1050 switch(Pool) {
1051 case WINED3DPOOL_SCRATCH:
1052 if(Lockable == FALSE)
1053 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1054 which are mutually exclusive, setting lockable to true\n");
1055 Lockable = TRUE;
1056 break;
1057 case WINED3DPOOL_SYSTEMMEM:
1058 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1059 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1060 case WINED3DPOOL_MANAGED:
1061 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1062 Usage of DYNAMIC which are mutually exclusive, not doing \
1063 anything just telling you.\n");
1064 break;
1065 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1066 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1067 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1068 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1069 break;
1070 default:
1071 FIXME("(%p) Unknown pool %d\n", This, Pool);
1072 break;
1075 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1076 FIXME("Trying to create a render target that isn't in the default pool\n");
1079 /* mark the texture as dirty so that it get's loaded first time around*/
1080 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1081 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1082 This, Width, Height, Format, debug_d3dformat(Format),
1083 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1085 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1086 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1087 This->ddraw_primary = (IWineD3DSurface *) object;
1089 /* Look at the implementation and set the correct Vtable */
1090 switch(Impl) {
1091 case SURFACE_OPENGL:
1092 /* Nothing to do, it's set already */
1093 break;
1095 case SURFACE_GDI:
1096 object->lpVtbl = &IWineGDISurface_Vtbl;
1097 break;
1099 default:
1100 /* To be sure to catch this */
1101 ERR("Unknown requested surface implementation %d!\n", Impl);
1102 IWineD3DSurface_Release((IWineD3DSurface *) object);
1103 return WINED3DERR_INVALIDCALL;
1106 /* Call the private setup routine */
1107 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1111 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1112 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1113 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1114 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1117 IWineD3DTextureImpl *object;
1118 unsigned int i;
1119 UINT tmpW;
1120 UINT tmpH;
1121 HRESULT hr;
1122 unsigned int pow2Width = Width;
1123 unsigned int pow2Height = Height;
1126 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1128 /* TODO: It should only be possible to create textures for formats
1129 that are reported as supported */
1130 if (WINED3DFMT_UNKNOWN >= Format) {
1131 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1132 return WINED3DERR_INVALIDCALL;
1135 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1136 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 object->width = Width;
1138 object->height = Height;
1140 /** Non-power2 support **/
1141 /* Find the nearest pow2 match */
1142 pow2Width = pow2Height = 1;
1143 while (pow2Width < Width) pow2Width <<= 1;
1144 while (pow2Height < Height) pow2Height <<= 1;
1146 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1147 /* Precalculated scaling for 'faked' non power of two texture coords */
1148 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1149 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1150 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1152 /* Calculate levels for mip mapping */
1153 if (Levels == 0) {
1154 TRACE("calculating levels %d\n", object->baseTexture.levels);
1155 object->baseTexture.levels++;
1156 tmpW = Width;
1157 tmpH = Height;
1158 while (tmpW > 1 || tmpH > 1) {
1159 tmpW = max(1, tmpW >> 1);
1160 tmpH = max(1, tmpH >> 1);
1161 object->baseTexture.levels++;
1163 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1166 /* Generate all the surfaces */
1167 tmpW = Width;
1168 tmpH = Height;
1169 for (i = 0; i < object->baseTexture.levels; i++)
1171 /* use the callback to create the texture surface */
1172 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1173 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1174 FIXME("Failed to create surface %p\n", object);
1175 /* clean up */
1176 object->surfaces[i] = NULL;
1177 IWineD3DTexture_Release((IWineD3DTexture *)object);
1179 *ppTexture = NULL;
1180 return hr;
1183 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1184 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1185 /* calculate the next mipmap level */
1186 tmpW = max(1, tmpW >> 1);
1187 tmpH = max(1, tmpH >> 1);
1190 TRACE("(%p) : Created texture %p\n", This, object);
1191 return WINED3D_OK;
1194 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1195 UINT Width, UINT Height, UINT Depth,
1196 UINT Levels, DWORD Usage,
1197 WINED3DFORMAT Format, WINED3DPOOL Pool,
1198 IWineD3DVolumeTexture **ppVolumeTexture,
1199 HANDLE *pSharedHandle, IUnknown *parent,
1200 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1203 IWineD3DVolumeTextureImpl *object;
1204 unsigned int i;
1205 UINT tmpW;
1206 UINT tmpH;
1207 UINT tmpD;
1209 /* TODO: It should only be possible to create textures for formats
1210 that are reported as supported */
1211 if (WINED3DFMT_UNKNOWN >= Format) {
1212 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1213 return WINED3DERR_INVALIDCALL;
1216 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1217 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1219 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1220 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1222 object->width = Width;
1223 object->height = Height;
1224 object->depth = Depth;
1226 /* Calculate levels for mip mapping */
1227 if (Levels == 0) {
1228 object->baseTexture.levels++;
1229 tmpW = Width;
1230 tmpH = Height;
1231 tmpD = Depth;
1232 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1233 tmpW = max(1, tmpW >> 1);
1234 tmpH = max(1, tmpH >> 1);
1235 tmpD = max(1, tmpD >> 1);
1236 object->baseTexture.levels++;
1238 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1241 /* Generate all the surfaces */
1242 tmpW = Width;
1243 tmpH = Height;
1244 tmpD = Depth;
1246 for (i = 0; i < object->baseTexture.levels; i++)
1248 /* Create the volume */
1249 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1250 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1252 /* Set it's container to this object */
1253 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1255 /* calcualte the next mipmap level */
1256 tmpW = max(1, tmpW >> 1);
1257 tmpH = max(1, tmpH >> 1);
1258 tmpD = max(1, tmpD >> 1);
1261 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1262 TRACE("(%p) : Created volume texture %p\n", This, object);
1263 return WINED3D_OK;
1266 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1267 UINT Width, UINT Height, UINT Depth,
1268 DWORD Usage,
1269 WINED3DFORMAT Format, WINED3DPOOL Pool,
1270 IWineD3DVolume** ppVolume,
1271 HANDLE* pSharedHandle, IUnknown *parent) {
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1275 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1277 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1279 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1280 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1282 object->currentDesc.Width = Width;
1283 object->currentDesc.Height = Height;
1284 object->currentDesc.Depth = Depth;
1285 object->bytesPerPixel = formatDesc->bpp;
1287 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1288 object->lockable = TRUE;
1289 object->locked = FALSE;
1290 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1291 object->dirty = TRUE;
1293 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1297 UINT Levels, DWORD Usage,
1298 WINED3DFORMAT Format, WINED3DPOOL Pool,
1299 IWineD3DCubeTexture **ppCubeTexture,
1300 HANDLE *pSharedHandle, IUnknown *parent,
1301 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1305 unsigned int i, j;
1306 UINT tmpW;
1307 HRESULT hr;
1308 unsigned int pow2EdgeLength = EdgeLength;
1310 /* TODO: It should only be possible to create textures for formats
1311 that are reported as supported */
1312 if (WINED3DFMT_UNKNOWN >= Format) {
1313 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1314 return WINED3DERR_INVALIDCALL;
1317 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1318 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1320 TRACE("(%p) Create Cube Texture\n", This);
1322 /** Non-power2 support **/
1324 /* Find the nearest pow2 match */
1325 pow2EdgeLength = 1;
1326 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1328 object->edgeLength = EdgeLength;
1329 /* TODO: support for native non-power 2 */
1330 /* Precalculated scaling for 'faked' non power of two texture coords */
1331 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1333 /* Calculate levels for mip mapping */
1334 if (Levels == 0) {
1335 object->baseTexture.levels++;
1336 tmpW = EdgeLength;
1337 while (tmpW > 1) {
1338 tmpW = max(1, tmpW >> 1);
1339 object->baseTexture.levels++;
1341 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1344 /* Generate all the surfaces */
1345 tmpW = EdgeLength;
1346 for (i = 0; i < object->baseTexture.levels; i++) {
1348 /* Create the 6 faces */
1349 for (j = 0; j < 6; j++) {
1351 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1352 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1354 if(hr!= WINED3D_OK) {
1355 /* clean up */
1356 int k;
1357 int l;
1358 for (l = 0; l < j; l++) {
1359 IWineD3DSurface_Release(object->surfaces[j][i]);
1361 for (k = 0; k < i; k++) {
1362 for (l = 0; l < 6; l++) {
1363 IWineD3DSurface_Release(object->surfaces[l][j]);
1367 FIXME("(%p) Failed to create surface\n",object);
1368 HeapFree(GetProcessHeap(),0,object);
1369 *ppCubeTexture = NULL;
1370 return hr;
1372 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1373 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1375 tmpW = max(1, tmpW >> 1);
1378 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1379 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1380 return WINED3D_OK;
1383 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1385 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1387 if (NULL == ppQuery) {
1388 /* Just a check to see if we support this type of query */
1389 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1390 switch(Type) {
1391 case WINED3DQUERYTYPE_OCCLUSION:
1392 TRACE("(%p) occlusion query\n", This);
1393 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1394 hr = WINED3D_OK;
1395 else
1396 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1397 break;
1398 case WINED3DQUERYTYPE_VCACHE:
1399 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1400 case WINED3DQUERYTYPE_VERTEXSTATS:
1401 case WINED3DQUERYTYPE_EVENT:
1402 case WINED3DQUERYTYPE_TIMESTAMP:
1403 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1404 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1405 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1406 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1407 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1408 case WINED3DQUERYTYPE_PIXELTIMINGS:
1409 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1410 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1411 default:
1412 FIXME("(%p) Unhandled query type %d\n", This, Type);
1414 return hr;
1417 D3DCREATEOBJECTINSTANCE(object, Query)
1418 object->type = Type;
1419 /* allocated the 'extended' data based on the type of query requested */
1420 switch(Type){
1421 case D3DQUERYTYPE_OCCLUSION:
1422 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1423 TRACE("(%p) Allocating data for an occlusion query\n", This);
1424 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1425 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1426 break;
1428 case D3DQUERYTYPE_VCACHE:
1429 case D3DQUERYTYPE_RESOURCEMANAGER:
1430 case D3DQUERYTYPE_VERTEXSTATS:
1431 case D3DQUERYTYPE_EVENT:
1432 case D3DQUERYTYPE_TIMESTAMP:
1433 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1434 case D3DQUERYTYPE_TIMESTAMPFREQ:
1435 case D3DQUERYTYPE_PIPELINETIMINGS:
1436 case D3DQUERYTYPE_INTERFACETIMINGS:
1437 case D3DQUERYTYPE_VERTEXTIMINGS:
1438 case D3DQUERYTYPE_PIXELTIMINGS:
1439 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1440 case D3DQUERYTYPE_CACHEUTILIZATION:
1441 default:
1442 object->extendedData = 0;
1443 FIXME("(%p) Unhandled query type %d\n",This , Type);
1445 TRACE("(%p) : Created Query %p\n", This, object);
1446 return WINED3D_OK;
1449 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1450 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1451 IUnknown* parent,
1452 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1453 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1456 HDC hDc;
1457 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1458 int num;
1459 XVisualInfo template;
1460 GLXContext oldContext;
1461 Drawable oldDrawable;
1462 HRESULT hr = WINED3D_OK;
1464 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1466 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1467 * does a device hold a reference to a swap chain giving them a lifetime of the device
1468 * or does the swap chain notify the device of its destruction.
1469 *******************************/
1471 /* Check the params */
1472 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1473 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1474 return WINED3DERR_INVALIDCALL;
1475 } else if (*pPresentationParameters->BackBufferCount > 1) {
1476 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");
1479 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1481 /*********************
1482 * Lookup the window Handle and the relating X window handle
1483 ********************/
1485 /* Setup hwnd we are using, plus which display this equates to */
1486 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1487 if (!object->win_handle) {
1488 object->win_handle = This->createParms.hFocusWindow;
1491 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1492 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1493 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1494 return WINED3DERR_NOTAVAILABLE;
1496 hDc = GetDC(object->win_handle);
1497 object->display = get_display(hDc);
1498 ReleaseDC(object->win_handle, hDc);
1499 TRACE("Using a display of %p %p\n", object->display, hDc);
1501 if (NULL == object->display || NULL == hDc) {
1502 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1503 return WINED3DERR_NOTAVAILABLE;
1506 if (object->win == 0) {
1507 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1508 return WINED3DERR_NOTAVAILABLE;
1511 * Create an opengl context for the display visual
1512 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1513 * use different properties after that point in time. FIXME: How to handle when requested format
1514 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1515 * it chooses is identical to the one already being used!
1516 **********************************/
1518 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1519 ENTER_GL();
1521 /* Create a new context for this swapchain */
1522 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1523 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1524 (or the best possible if none is requested) */
1525 TRACE("Found x visual ID : %ld\n", template.visualid);
1527 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1528 if (NULL == object->visInfo) {
1529 ERR("cannot really get XVisual\n");
1530 LEAVE_GL();
1531 return WINED3DERR_NOTAVAILABLE;
1532 } else {
1533 int n, value;
1534 /* Write out some debug info about the visual/s */
1535 TRACE("Using x visual ID : %ld\n", template.visualid);
1536 TRACE(" visual info: %p\n", object->visInfo);
1537 TRACE(" num items : %d\n", num);
1538 for (n = 0;n < num; n++) {
1539 TRACE("=====item=====: %d\n", n + 1);
1540 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1541 TRACE(" screen : %d\n", object->visInfo[n].screen);
1542 TRACE(" depth : %u\n", object->visInfo[n].depth);
1543 TRACE(" class : %d\n", object->visInfo[n].class);
1544 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1545 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1546 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1547 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1548 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1549 /* log some extra glx info */
1550 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1551 TRACE(" gl_aux_buffers : %d\n", value);
1552 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1553 TRACE(" gl_buffer_size : %d\n", value);
1554 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1555 TRACE(" gl_red_size : %d\n", value);
1556 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1557 TRACE(" gl_green_size : %d\n", value);
1558 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1559 TRACE(" gl_blue_size : %d\n", value);
1560 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1561 TRACE(" gl_alpha_size : %d\n", value);
1562 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1563 TRACE(" gl_depth_size : %d\n", value);
1564 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1565 TRACE(" gl_stencil_size : %d\n", value);
1567 /* Now choose a simila visual ID*/
1569 #ifdef USE_CONTEXT_MANAGER
1571 /** TODO: use a context mamager **/
1572 #endif
1575 IWineD3DSwapChain *implSwapChain;
1576 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1577 /* The first time around we create the context that is shared with all other swapchains and render targets */
1578 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1579 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1580 } else {
1582 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1583 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1584 /* and create a new context with the implicit swapchains context as the shared context */
1585 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1586 IWineD3DSwapChain_Release(implSwapChain);
1590 /* Cleanup */
1591 XFree(object->visInfo);
1592 object->visInfo = NULL;
1594 LEAVE_GL();
1596 if (!object->glCtx) {
1597 ERR("Failed to create GLX context\n");
1598 return WINED3DERR_NOTAVAILABLE;
1599 } else {
1600 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1601 object->win_handle, object->glCtx, object->win, object->visInfo);
1604 /*********************
1605 * Windowed / Fullscreen
1606 *******************/
1609 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1610 * so we should really check to see if there is a fullscreen swapchain already
1611 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1612 **************************************/
1614 if (!*(pPresentationParameters->Windowed)) {
1616 DEVMODEW devmode;
1617 HDC hdc;
1618 int bpp = 0;
1620 /* Get info on the current display setup */
1621 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1622 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1623 DeleteDC(hdc);
1625 /* Change the display settings */
1626 memset(&devmode, 0, sizeof(DEVMODEW));
1627 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1628 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1629 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1630 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1631 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1632 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1634 /* Make popup window */
1635 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1636 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1637 *(pPresentationParameters->BackBufferWidth),
1638 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1640 /* For GetDisplayMode */
1641 This->ddraw_width = devmode.dmPelsWidth;
1642 This->ddraw_height = devmode.dmPelsHeight;
1643 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1647 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1648 * then the corresponding dimension of the client area of the hDeviceWindow
1649 * (or the focus window, if hDeviceWindow is NULL) is taken.
1650 **********************/
1652 if (*(pPresentationParameters->Windowed) &&
1653 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1654 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1656 RECT Rect;
1657 GetClientRect(object->win_handle, &Rect);
1659 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1660 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1661 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1663 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1664 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1665 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1669 /*********************
1670 * finish off parameter initialization
1671 *******************/
1673 /* Put the correct figures in the presentation parameters */
1674 TRACE("Coppying accross presentaion paraneters\n");
1675 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1676 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1677 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1678 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1679 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1680 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1681 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1682 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1683 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1684 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1685 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1686 object->presentParms.Flags = *(pPresentationParameters->Flags);
1687 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1688 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1691 /*********************
1692 * Create the back, front and stencil buffers
1693 *******************/
1695 TRACE("calling rendertarget CB\n");
1696 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1697 object->presentParms.BackBufferWidth,
1698 object->presentParms.BackBufferHeight,
1699 object->presentParms.BackBufferFormat,
1700 object->presentParms.MultiSampleType,
1701 object->presentParms.MultiSampleQuality,
1702 TRUE /* Lockable */,
1703 &object->frontBuffer,
1704 NULL /* pShared (always null)*/);
1705 if (object->frontBuffer != NULL)
1706 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1708 if(object->presentParms.BackBufferCount > 0) {
1709 int i;
1711 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1712 if(!object->backBuffer) {
1713 ERR("Out of memory\n");
1715 if (object->frontBuffer) {
1716 IUnknown *bufferParent;
1717 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1718 IUnknown_Release(bufferParent); /* once for the get parent */
1719 if (IUnknown_Release(bufferParent) > 0) {
1720 FIXME("(%p) Something's still holding the front buffer\n",This);
1723 HeapFree(GetProcessHeap(), 0, object);
1724 return E_OUTOFMEMORY;
1727 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1728 TRACE("calling rendertarget CB\n");
1729 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1730 object->presentParms.BackBufferWidth,
1731 object->presentParms.BackBufferHeight,
1732 object->presentParms.BackBufferFormat,
1733 object->presentParms.MultiSampleType,
1734 object->presentParms.MultiSampleQuality,
1735 TRUE /* Lockable */,
1736 &object->backBuffer[i],
1737 NULL /* pShared (always null)*/);
1738 if(hr == WINED3D_OK && object->backBuffer[i]) {
1739 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1740 } else {
1741 break;
1744 } else {
1745 object->backBuffer = NULL;
1748 if (object->backBuffer != NULL) {
1749 ENTER_GL();
1750 glDrawBuffer(GL_BACK);
1751 checkGLcall("glDrawBuffer(GL_BACK)");
1752 LEAVE_GL();
1753 } else {
1754 /* Single buffering - draw to front buffer */
1755 ENTER_GL();
1756 glDrawBuffer(GL_FRONT);
1757 checkGLcall("glDrawBuffer(GL_FRONT)");
1758 LEAVE_GL();
1761 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1762 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1763 TRACE("Creating depth stencil buffer\n");
1764 if (This->depthStencilBuffer == NULL ) {
1765 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1766 object->presentParms.BackBufferWidth,
1767 object->presentParms.BackBufferHeight,
1768 object->presentParms.AutoDepthStencilFormat,
1769 object->presentParms.MultiSampleType,
1770 object->presentParms.MultiSampleQuality,
1771 FALSE /* FIXME: Discard */,
1772 &This->depthStencilBuffer,
1773 NULL /* pShared (always null)*/ );
1774 if (This->depthStencilBuffer != NULL)
1775 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1778 /** TODO: A check on width, height and multisample types
1779 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1780 ****************************/
1781 object->wantsDepthStencilBuffer = TRUE;
1782 } else {
1783 object->wantsDepthStencilBuffer = FALSE;
1786 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1789 /*********************
1790 * init the default renderTarget management
1791 *******************/
1792 object->drawable = object->win;
1793 object->render_ctx = object->glCtx;
1795 if (hr == WINED3D_OK) {
1796 /*********************
1797 * Setup some defaults and clear down the buffers
1798 *******************/
1799 ENTER_GL();
1800 /** save current context and drawable **/
1801 oldContext = glXGetCurrentContext();
1802 oldDrawable = glXGetCurrentDrawable();
1804 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1805 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1806 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1808 checkGLcall("glXMakeCurrent");
1810 TRACE("Setting up the screen\n");
1811 /* Clear the screen */
1812 glClearColor(1.0, 0.0, 0.0, 0.0);
1813 checkGLcall("glClearColor");
1814 glClearIndex(0);
1815 glClearDepth(1);
1816 glClearStencil(0xffff);
1818 checkGLcall("glClear");
1820 glColor3f(1.0, 1.0, 1.0);
1821 checkGLcall("glColor3f");
1823 glEnable(GL_LIGHTING);
1824 checkGLcall("glEnable");
1826 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1827 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1829 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1830 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1832 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1833 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1835 /* switch back to the original context (if there was one)*/
1836 if (This->swapchains) {
1837 /** TODO: restore the context and drawable **/
1838 glXMakeCurrent(object->display, oldDrawable, oldContext);
1841 LEAVE_GL();
1843 TRACE("Set swapchain to %p\n", object);
1844 } else { /* something went wrong so clean up */
1845 IUnknown* bufferParent;
1846 if (object->frontBuffer) {
1848 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1849 IUnknown_Release(bufferParent); /* once for the get parent */
1850 if (IUnknown_Release(bufferParent) > 0) {
1851 FIXME("(%p) Something's still holding the front buffer\n",This);
1854 if (object->backBuffer) {
1855 int i;
1856 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1857 if(object->backBuffer[i]) {
1858 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1859 IUnknown_Release(bufferParent); /* once for the get parent */
1860 if (IUnknown_Release(bufferParent) > 0) {
1861 FIXME("(%p) Something's still holding the back buffer\n",This);
1865 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1866 object->backBuffer = NULL;
1868 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1869 /* Clean up the context */
1870 /* check that we are the current context first (we shouldn't be though!) */
1871 if (object->glCtx != 0) {
1872 if(glXGetCurrentContext() == object->glCtx) {
1873 glXMakeCurrent(object->display, None, NULL);
1875 glXDestroyContext(object->display, object->glCtx);
1877 HeapFree(GetProcessHeap(), 0, object);
1881 return hr;
1884 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1885 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1887 TRACE("(%p)\n", This);
1889 return This->NumberOfSwapChains;
1892 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1894 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1896 if(iSwapChain < This->NumberOfSwapChains) {
1897 *pSwapChain = This->swapchains[iSwapChain];
1898 IWineD3DSwapChain_AddRef(*pSwapChain);
1899 TRACE("(%p) returning %p\n", This, *pSwapChain);
1900 return WINED3D_OK;
1901 } else {
1902 TRACE("Swapchain out of range\n");
1903 *pSwapChain = NULL;
1904 return WINED3DERR_INVALIDCALL;
1908 /*****
1909 * Vertex Declaration
1910 *****/
1911 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1913 IWineD3DVertexDeclarationImpl *object = NULL;
1914 HRESULT hr = WINED3D_OK;
1915 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1916 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1917 object->allFVF = 0;
1919 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1921 return hr;
1924 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1927 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1928 HRESULT hr = WINED3D_OK;
1929 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1930 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1932 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1934 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1935 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1936 if (pDeclaration != NULL) {
1937 IWineD3DVertexDeclaration *vertexDeclaration;
1938 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1939 if (WINED3D_OK == hr) {
1940 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1941 object->vertexDeclaration = vertexDeclaration;
1942 } else {
1943 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1944 IWineD3DVertexShader_Release(*ppVertexShader);
1945 return WINED3DERR_INVALIDCALL;
1949 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1951 if (WINED3D_OK != hr) {
1952 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1953 IWineD3DVertexShader_Release(*ppVertexShader);
1954 return WINED3DERR_INVALIDCALL;
1957 #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. */
1958 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1959 /* Foo */
1960 } else {
1961 /* Bar */
1964 #endif
1966 return WINED3D_OK;
1969 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1971 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1972 HRESULT hr = WINED3D_OK;
1974 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1975 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1976 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1977 if (WINED3D_OK == hr) {
1978 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1979 } else {
1980 WARN("(%p) : Failed to create pixel shader\n", This);
1983 return hr;
1986 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1988 IWineD3DPaletteImpl *object;
1989 HRESULT hr;
1990 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1992 /* Create the new object */
1993 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1994 if(!object) {
1995 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1996 return E_OUTOFMEMORY;
1999 object->lpVtbl = &IWineD3DPalette_Vtbl;
2000 object->ref = 1;
2001 object->Flags = Flags;
2002 object->parent = Parent;
2003 object->wineD3DDevice = This;
2004 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2006 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2008 if(!object->hpal) {
2009 HeapFree( GetProcessHeap(), 0, object);
2010 return E_OUTOFMEMORY;
2013 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2014 if(FAILED(hr)) {
2015 IWineD3DPalette_Release((IWineD3DPalette *) object);
2016 return hr;
2019 *Palette = (IWineD3DPalette *) object;
2021 return WINED3D_OK;
2024 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2026 IWineD3DSwapChainImpl *swapchain;
2028 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2029 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2031 /* TODO: Test if OpenGL is compiled in and loaded */
2033 /* Setup the implicit swapchain */
2034 TRACE("Creating implicit swapchain\n");
2035 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2036 WARN("Failed to create implicit swapchain\n");
2037 return WINED3DERR_INVALIDCALL;
2040 This->NumberOfSwapChains = 1;
2041 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2042 if(!This->swapchains) {
2043 ERR("Out of memory!\n");
2044 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2045 return E_OUTOFMEMORY;
2047 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2049 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2050 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2051 This->renderTarget = swapchain->backBuffer[0];
2053 else {
2054 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2055 This->renderTarget = swapchain->frontBuffer;
2057 IWineD3DSurface_AddRef(This->renderTarget);
2058 /* Depth Stencil support */
2059 This->stencilBufferTarget = This->depthStencilBuffer;
2060 if (NULL != This->stencilBufferTarget) {
2061 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2064 /* Set up some starting GL setup */
2065 ENTER_GL();
2067 * Initialize openGL extension related variables
2068 * with Default values
2071 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2072 /* Setup all the devices defaults */
2073 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2074 #if 0
2075 IWineD3DImpl_CheckGraphicsMemory();
2076 #endif
2077 LEAVE_GL();
2079 /* Initialize our list of GLSL programs */
2080 list_init(&This->glsl_shader_progs);
2082 { /* Set a default viewport */
2083 D3DVIEWPORT9 vp;
2084 vp.X = 0;
2085 vp.Y = 0;
2086 vp.Width = *(pPresentationParameters->BackBufferWidth);
2087 vp.Height = *(pPresentationParameters->BackBufferHeight);
2088 vp.MinZ = 0.0f;
2089 vp.MaxZ = 1.0f;
2090 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2093 /* Initialize the current view state */
2094 This->modelview_valid = 1;
2095 This->proj_valid = 0;
2096 This->view_ident = 1;
2097 This->last_was_rhw = 0;
2098 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2099 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2101 /* Clear the screen */
2102 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2104 This->d3d_initialized = TRUE;
2105 return WINED3D_OK;
2108 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2110 int sampler;
2111 IUnknown* stencilBufferParent;
2112 IUnknown* swapChainParent;
2113 uint i;
2114 TRACE("(%p)\n", This);
2116 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2118 /* Delete the mouse cursor texture */
2119 if(This->cursorTexture) {
2120 ENTER_GL();
2121 glDeleteTextures(1, &This->cursorTexture);
2122 LEAVE_GL();
2123 This->cursorTexture = 0;
2126 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2127 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2130 /* Release the buffers (with sanity checks)*/
2131 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2132 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2133 if(This->depthStencilBuffer != This->stencilBufferTarget)
2134 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2136 This->stencilBufferTarget = NULL;
2138 TRACE("Releasing the render target at %p\n", This->renderTarget);
2139 if(IWineD3DSurface_Release(This->renderTarget) >0){
2140 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2142 TRACE("Setting rendertarget to NULL\n");
2143 This->renderTarget = NULL;
2145 if (This->depthStencilBuffer) {
2146 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2147 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2148 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2149 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2151 This->depthStencilBuffer = NULL;
2154 for(i=0; i < This->NumberOfSwapChains; i++) {
2155 TRACE("Releasing the implicit swapchain %d\n", i);
2156 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2157 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2158 IUnknown_Release(swapChainParent); /* once for the get parent */
2159 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2160 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2164 HeapFree(GetProcessHeap(), 0, This->swapchains);
2165 This->swapchains = NULL;
2166 This->NumberOfSwapChains = 0;
2168 This->d3d_initialized = FALSE;
2169 return WINED3D_OK;
2172 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2175 DEVMODEW DevModeW;
2176 int i;
2177 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2179 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2181 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2182 /* Ignore some modes if a description was passed */
2183 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2184 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2185 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2187 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2189 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2190 return D3D_OK;
2193 return D3D_OK;
2196 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2197 DEVMODEW devmode;
2198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2199 LONG ret;
2200 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2202 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2204 /* Resize the screen even without a window:
2205 * The app could have unset it with SetCooperativeLevel, but not called
2206 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2207 * but we don't have any hwnd
2210 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2211 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2212 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2213 devmode.dmPelsWidth = pMode->Width;
2214 devmode.dmPelsHeight = pMode->Height;
2216 devmode.dmDisplayFrequency = pMode->RefreshRate;
2217 if (pMode->RefreshRate != 0) {
2218 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2221 /* Only change the mode if necessary */
2222 if( (This->ddraw_width == pMode->Width) &&
2223 (This->ddraw_height == pMode->Height) &&
2224 (This->ddraw_format == pMode->Format) &&
2225 (pMode->RefreshRate == 0) ) {
2226 return D3D_OK;
2229 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2230 if (ret != DISP_CHANGE_SUCCESSFUL) {
2231 if(devmode.dmDisplayFrequency != 0) {
2232 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2233 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2234 devmode.dmDisplayFrequency = 0;
2235 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2237 if(ret != DISP_CHANGE_SUCCESSFUL) {
2238 return DDERR_INVALIDMODE;
2242 /* Store the new values */
2243 This->ddraw_width = pMode->Width;
2244 This->ddraw_height = pMode->Height;
2245 This->ddraw_format = pMode->Format;
2247 /* Only do this with a window of course */
2248 if(This->ddraw_window)
2249 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2251 return WINED3D_OK;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2256 *ppD3D= This->wineD3D;
2257 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2258 IWineD3D_AddRef(*ppD3D);
2259 return WINED3D_OK;
2262 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2263 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2264 * Into the video ram as possible and seeing how many fit
2265 * you can also get the correct initial value from via X and ATI's driver
2266 *******************/
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2268 static BOOL showfixmes = TRUE;
2269 if (showfixmes) {
2270 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2271 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2272 showfixmes = FALSE;
2274 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2275 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2276 /* videomemory is simulated videomemory + AGP memory left */
2277 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2282 /*****
2283 * Get / Set FVF
2284 *****/
2285 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2287 HRESULT hr = WINED3D_OK;
2289 /* Update the current state block */
2290 This->updateStateBlock->fvf = fvf;
2291 This->updateStateBlock->changed.fvf = TRUE;
2292 This->updateStateBlock->set.fvf = TRUE;
2294 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2295 return hr;
2299 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2301 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2302 *pfvf = This->stateBlock->fvf;
2303 return WINED3D_OK;
2306 /*****
2307 * Get / Set Stream Source
2308 *****/
2309 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2311 IWineD3DVertexBuffer *oldSrc;
2313 /**TODO: instance and index data, see
2314 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2316 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2317 **************/
2319 /* D3d9 only, but shouldn't hurt d3d8 */
2320 UINT streamFlags;
2322 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2323 if (streamFlags) {
2324 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2325 FIXME("stream index data not supported\n");
2327 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2328 FIXME("stream instance data not supported\n");
2332 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2334 if (StreamNumber >= MAX_STREAMS) {
2335 WARN("Stream out of range %d\n", StreamNumber);
2336 return WINED3DERR_INVALIDCALL;
2339 oldSrc = This->stateBlock->streamSource[StreamNumber];
2340 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2342 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2343 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2344 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2345 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2346 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2347 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2349 /* Handle recording of state blocks */
2350 if (This->isRecordingState) {
2351 TRACE("Recording... not performing anything\n");
2352 return WINED3D_OK;
2355 /* Same stream object: no action */
2356 if (oldSrc == pStreamData)
2357 return WINED3D_OK;
2359 /* Need to do a getParent and pass the reffs up */
2360 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2361 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2362 so for now, just count internally */
2363 if (pStreamData != NULL) {
2364 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2365 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2366 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2368 vbImpl->stream = StreamNumber;
2369 vbImpl->Flags |= VBFLAG_STREAM;
2370 IWineD3DVertexBuffer_AddRef(pStreamData);
2372 if (oldSrc != NULL) {
2373 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2374 IWineD3DVertexBuffer_Release(oldSrc);
2377 return WINED3D_OK;
2380 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2382 UINT streamFlags;
2384 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2385 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2388 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2389 if (streamFlags) {
2390 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2391 FIXME("stream index data not supported\n");
2393 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2394 FIXME("stream instance data not supported\n");
2398 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2400 if (StreamNumber >= MAX_STREAMS) {
2401 WARN("Stream out of range %d\n", StreamNumber);
2402 return WINED3DERR_INVALIDCALL;
2404 *pStream = This->stateBlock->streamSource[StreamNumber];
2405 *pStride = This->stateBlock->streamStride[StreamNumber];
2406 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2408 if (*pStream == NULL) {
2409 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2410 return WINED3DERR_INVALIDCALL;
2413 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2414 return WINED3D_OK;
2417 /*Should be quite easy, just an extension of vertexdata
2418 ref...
2419 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2421 The divider is a bit odd though
2423 VertexOffset = StartVertex / Divider * StreamStride +
2424 VertexIndex / Divider * StreamStride + StreamOffset
2427 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2431 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2433 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2434 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2435 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2437 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2438 FIXME("Stream indexing not fully supported\n");
2441 return WINED3D_OK;
2444 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2447 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2448 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2450 TRACE("(%p) : returning %d\n", This, *Divider);
2452 return WINED3D_OK;
2455 /*****
2456 * Get / Set & Multiply Transform
2457 *****/
2458 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 /* Most of this routine, comments included copied from ddraw tree initially: */
2462 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2464 /* Handle recording of state blocks */
2465 if (This->isRecordingState) {
2466 TRACE("Recording... not performing anything\n");
2467 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2468 This->updateStateBlock->set.transform[d3dts] = TRUE;
2469 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2470 return WINED3D_OK;
2474 * If the new matrix is the same as the current one,
2475 * we cut off any further processing. this seems to be a reasonable
2476 * optimization because as was noticed, some apps (warcraft3 for example)
2477 * tend towards setting the same matrix repeatedly for some reason.
2479 * From here on we assume that the new matrix is different, wherever it matters.
2481 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2482 TRACE("The app is setting the same matrix over again\n");
2483 return WINED3D_OK;
2484 } else {
2485 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2489 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2490 where ViewMat = Camera space, WorldMat = world space.
2492 In OpenGL, camera and world space is combined into GL_MODELVIEW
2493 matrix. The Projection matrix stay projection matrix.
2496 /* Capture the times we can just ignore the change for now */
2497 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2498 This->modelview_valid = FALSE;
2499 return WINED3D_OK;
2501 } else if (d3dts == WINED3DTS_PROJECTION) {
2502 This->proj_valid = FALSE;
2503 return WINED3D_OK;
2505 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2506 /* Indexed Vertex Blending Matrices 256 -> 511 */
2507 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2508 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2509 return WINED3D_OK;
2512 /* Now we really are going to have to change a matrix */
2513 ENTER_GL();
2515 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2516 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2517 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2518 unsigned int k;
2520 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2521 * NOTE: We have to reset the positions even if the light/plane is not currently
2522 * enabled, since the call to enable it will not reset the position.
2523 * NOTE2: Apparently texture transforms do NOT need reapplying
2526 PLIGHTINFOEL *lightChain = NULL;
2527 This->modelview_valid = FALSE;
2528 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2530 glMatrixMode(GL_MODELVIEW);
2531 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2532 glPushMatrix();
2533 glLoadMatrixf((float *)lpmatrix);
2534 checkGLcall("glLoadMatrixf(...)");
2536 /* Reset lights */
2537 lightChain = This->stateBlock->lights;
2538 while (lightChain && lightChain->glIndex != -1) {
2539 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2540 checkGLcall("glLightfv posn");
2541 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2542 checkGLcall("glLightfv dirn");
2543 lightChain = lightChain->next;
2546 /* Reset Clipping Planes if clipping is enabled */
2547 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2548 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2549 checkGLcall("glClipPlane");
2551 glPopMatrix();
2553 } else { /* What was requested!?? */
2554 WARN("invalid matrix specified: %i\n", d3dts);
2557 /* Release lock, all done */
2558 LEAVE_GL();
2559 return WINED3D_OK;
2562 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2565 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2566 return WINED3D_OK;
2569 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2570 D3DMATRIX *mat = NULL;
2571 D3DMATRIX temp;
2573 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2574 * below means it will be recorded in a state block change, but it
2575 * works regardless where it is recorded.
2576 * If this is found to be wrong, change to StateBlock.
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2579 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2581 if (State < HIGHEST_TRANSFORMSTATE)
2583 mat = &This->updateStateBlock->transforms[State];
2584 } else {
2585 FIXME("Unhandled transform state!!\n");
2588 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2590 /* Apply change via set transform - will reapply to eg. lights this way */
2591 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2594 /*****
2595 * Get / Set Light
2596 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2597 *****/
2598 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2599 you can reference any indexes you want as long as that number max are enabled at any
2600 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2601 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2602 but when recording, just build a chain pretty much of commands to be replayed. */
2604 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2605 float rho;
2606 PLIGHTINFOEL *object, *temp;
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2611 /* If recording state block, just add to end of lights chain */
2612 if (This->isRecordingState) {
2613 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2614 if (NULL == object) {
2615 return WINED3DERR_OUTOFVIDEOMEMORY;
2617 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2618 object->OriginalIndex = Index;
2619 object->glIndex = -1;
2620 object->changed = TRUE;
2622 /* Add to the END of the chain of lights changes to be replayed */
2623 if (This->updateStateBlock->lights == NULL) {
2624 This->updateStateBlock->lights = object;
2625 } else {
2626 temp = This->updateStateBlock->lights;
2627 while (temp->next != NULL) temp=temp->next;
2628 temp->next = object;
2630 TRACE("Recording... not performing anything more\n");
2631 return WINED3D_OK;
2634 /* Ok, not recording any longer so do real work */
2635 object = This->stateBlock->lights;
2636 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2638 /* If we didn't find it in the list of lights, time to add it */
2639 if (object == NULL) {
2640 PLIGHTINFOEL *insertAt,*prevPos;
2642 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2643 if (NULL == object) {
2644 return WINED3DERR_OUTOFVIDEOMEMORY;
2646 object->OriginalIndex = Index;
2647 object->glIndex = -1;
2649 /* Add it to the front of list with the idea that lights will be changed as needed
2650 BUT after any lights currently assigned GL indexes */
2651 insertAt = This->stateBlock->lights;
2652 prevPos = NULL;
2653 while (insertAt != NULL && insertAt->glIndex != -1) {
2654 prevPos = insertAt;
2655 insertAt = insertAt->next;
2658 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2659 This->stateBlock->lights = object;
2660 } else if (insertAt == NULL) { /* End of list */
2661 prevPos->next = object;
2662 object->prev = prevPos;
2663 } else { /* Middle of chain */
2664 if (prevPos == NULL) {
2665 This->stateBlock->lights = object;
2666 } else {
2667 prevPos->next = object;
2669 object->prev = prevPos;
2670 object->next = insertAt;
2671 insertAt->prev = object;
2675 /* Initialize the object */
2676 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,
2677 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2678 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2679 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2680 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2681 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2682 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2684 /* Save away the information */
2685 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2687 switch (pLight->Type) {
2688 case D3DLIGHT_POINT:
2689 /* Position */
2690 object->lightPosn[0] = pLight->Position.x;
2691 object->lightPosn[1] = pLight->Position.y;
2692 object->lightPosn[2] = pLight->Position.z;
2693 object->lightPosn[3] = 1.0f;
2694 object->cutoff = 180.0f;
2695 /* FIXME: Range */
2696 break;
2698 case D3DLIGHT_DIRECTIONAL:
2699 /* Direction */
2700 object->lightPosn[0] = -pLight->Direction.x;
2701 object->lightPosn[1] = -pLight->Direction.y;
2702 object->lightPosn[2] = -pLight->Direction.z;
2703 object->lightPosn[3] = 0.0;
2704 object->exponent = 0.0f;
2705 object->cutoff = 180.0f;
2706 break;
2708 case D3DLIGHT_SPOT:
2709 /* Position */
2710 object->lightPosn[0] = pLight->Position.x;
2711 object->lightPosn[1] = pLight->Position.y;
2712 object->lightPosn[2] = pLight->Position.z;
2713 object->lightPosn[3] = 1.0;
2715 /* Direction */
2716 object->lightDirn[0] = pLight->Direction.x;
2717 object->lightDirn[1] = pLight->Direction.y;
2718 object->lightDirn[2] = pLight->Direction.z;
2719 object->lightDirn[3] = 1.0;
2722 * opengl-ish and d3d-ish spot lights use too different models for the
2723 * light "intensity" as a function of the angle towards the main light direction,
2724 * so we only can approximate very roughly.
2725 * however spot lights are rather rarely used in games (if ever used at all).
2726 * furthermore if still used, probably nobody pays attention to such details.
2728 if (pLight->Falloff == 0) {
2729 rho = 6.28f;
2730 } else {
2731 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2733 if (rho < 0.0001) rho = 0.0001f;
2734 object->exponent = -0.3/log(cos(rho/2));
2735 object->cutoff = pLight->Phi*90/M_PI;
2737 /* FIXME: Range */
2738 break;
2740 default:
2741 FIXME("Unrecognized light type %d\n", pLight->Type);
2744 /* Update the live definitions if the light is currently assigned a glIndex */
2745 if (object->glIndex != -1) {
2746 setup_light(iface, object->glIndex, object);
2748 return WINED3D_OK;
2751 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2752 PLIGHTINFOEL *lightInfo = NULL;
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2756 /* Locate the light in the live lights */
2757 lightInfo = This->stateBlock->lights;
2758 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2760 if (lightInfo == NULL) {
2761 TRACE("Light information requested but light not defined\n");
2762 return WINED3DERR_INVALIDCALL;
2765 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2766 return WINED3D_OK;
2769 /*****
2770 * Get / Set Light Enable
2771 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2772 *****/
2773 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2774 PLIGHTINFOEL *lightInfo = NULL;
2775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2776 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2778 /* Tests show true = 128...not clear why */
2780 Enable = Enable? 128: 0;
2782 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2783 if (This->isRecordingState) {
2784 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2785 if (NULL == lightInfo) {
2786 return WINED3DERR_OUTOFVIDEOMEMORY;
2788 lightInfo->OriginalIndex = Index;
2789 lightInfo->glIndex = -1;
2790 lightInfo->enabledChanged = TRUE;
2791 lightInfo->lightEnabled = Enable;
2793 /* Add to the END of the chain of lights changes to be replayed */
2794 if (This->updateStateBlock->lights == NULL) {
2795 This->updateStateBlock->lights = lightInfo;
2796 } else {
2797 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2798 while (temp->next != NULL) temp=temp->next;
2799 temp->next = lightInfo;
2801 TRACE("Recording... not performing anything more\n");
2802 return WINED3D_OK;
2805 /* Not recording... So, locate the light in the live lights */
2806 lightInfo = This->stateBlock->lights;
2807 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2809 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2810 if (lightInfo == NULL) {
2812 TRACE("Light enabled requested but light not defined, so defining one!\n");
2813 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2815 /* Search for it again! Should be fairly quick as near head of list */
2816 lightInfo = This->stateBlock->lights;
2817 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2818 if (lightInfo == NULL) {
2819 FIXME("Adding default lights has failed dismally\n");
2820 return WINED3DERR_INVALIDCALL;
2824 /* OK, we now have a light... */
2825 if (Enable == FALSE) {
2827 /* If we are disabling it, check it was enabled, and
2828 still only do something if it has assigned a glIndex (which it should have!) */
2829 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2830 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2831 ENTER_GL();
2832 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2833 checkGLcall("glDisable GL_LIGHT0+Index");
2834 LEAVE_GL();
2835 } else {
2836 TRACE("Nothing to do as light was not enabled\n");
2838 lightInfo->lightEnabled = Enable;
2839 } else {
2841 /* We are enabling it. If it is enabled, it's really simple */
2842 if (lightInfo->lightEnabled) {
2843 /* nop */
2844 TRACE("Nothing to do as light was enabled\n");
2846 /* If it already has a glIndex, it's still simple */
2847 } else if (lightInfo->glIndex != -1) {
2848 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2849 lightInfo->lightEnabled = Enable;
2850 ENTER_GL();
2851 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2852 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2853 LEAVE_GL();
2855 /* Otherwise got to find space - lights are ordered gl indexes first */
2856 } else {
2857 PLIGHTINFOEL *bsf = NULL;
2858 PLIGHTINFOEL *pos = This->stateBlock->lights;
2859 PLIGHTINFOEL *prev = NULL;
2860 int Index= 0;
2861 int glIndex = -1;
2863 /* Try to minimize changes as much as possible */
2864 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2866 /* Try to remember which index can be replaced if necessary */
2867 if (bsf==NULL && pos->lightEnabled == FALSE) {
2868 /* Found a light we can replace, save as best replacement */
2869 bsf = pos;
2872 /* Step to next space */
2873 prev = pos;
2874 pos = pos->next;
2875 Index ++;
2878 /* If we have too many active lights, fail the call */
2879 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2880 FIXME("Program requests too many concurrent lights\n");
2881 return WINED3DERR_INVALIDCALL;
2883 /* If we have allocated all lights, but not all are enabled,
2884 reuse one which is not enabled */
2885 } else if (Index == This->maxConcurrentLights) {
2886 /* use bsf - Simply swap the new light and the BSF one */
2887 PLIGHTINFOEL *bsfNext = bsf->next;
2888 PLIGHTINFOEL *bsfPrev = bsf->prev;
2890 /* Sort out ends */
2891 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2892 if (bsf->prev != NULL) {
2893 bsf->prev->next = lightInfo;
2894 } else {
2895 This->stateBlock->lights = lightInfo;
2898 /* If not side by side, lots of chains to update */
2899 if (bsf->next != lightInfo) {
2900 lightInfo->prev->next = bsf;
2901 bsf->next->prev = lightInfo;
2902 bsf->next = lightInfo->next;
2903 bsf->prev = lightInfo->prev;
2904 lightInfo->next = bsfNext;
2905 lightInfo->prev = bsfPrev;
2907 } else {
2908 /* Simple swaps */
2909 bsf->prev = lightInfo;
2910 bsf->next = lightInfo->next;
2911 lightInfo->next = bsf;
2912 lightInfo->prev = bsfPrev;
2916 /* Update states */
2917 glIndex = bsf->glIndex;
2918 bsf->glIndex = -1;
2919 lightInfo->glIndex = glIndex;
2920 lightInfo->lightEnabled = Enable;
2922 /* Finally set up the light in gl itself */
2923 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2924 ENTER_GL();
2925 setup_light(iface, glIndex, lightInfo);
2926 glEnable(GL_LIGHT0 + glIndex);
2927 checkGLcall("glEnable GL_LIGHT0 new setup");
2928 LEAVE_GL();
2930 /* If we reached the end of the allocated lights, with space in the
2931 gl lights, setup a new light */
2932 } else if (pos->glIndex == -1) {
2934 /* We reached the end of the allocated gl lights, so already
2935 know the index of the next one! */
2936 glIndex = Index;
2937 lightInfo->glIndex = glIndex;
2938 lightInfo->lightEnabled = Enable;
2940 /* In an ideal world, it's already in the right place */
2941 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2942 /* No need to move it */
2943 } else {
2944 /* Remove this light from the list */
2945 lightInfo->prev->next = lightInfo->next;
2946 if (lightInfo->next != NULL) {
2947 lightInfo->next->prev = lightInfo->prev;
2950 /* Add in at appropriate place (inbetween prev and pos) */
2951 lightInfo->prev = prev;
2952 lightInfo->next = pos;
2953 if (prev == NULL) {
2954 This->stateBlock->lights = lightInfo;
2955 } else {
2956 prev->next = lightInfo;
2958 if (pos != NULL) {
2959 pos->prev = lightInfo;
2963 /* Finally set up the light in gl itself */
2964 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2965 ENTER_GL();
2966 setup_light(iface, glIndex, lightInfo);
2967 glEnable(GL_LIGHT0 + glIndex);
2968 checkGLcall("glEnable GL_LIGHT0 new setup");
2969 LEAVE_GL();
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2979 PLIGHTINFOEL *lightInfo = NULL;
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 TRACE("(%p) : for idx(%ld)\n", This, Index);
2983 /* Locate the light in the live lights */
2984 lightInfo = This->stateBlock->lights;
2985 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2987 if (lightInfo == NULL) {
2988 TRACE("Light enabled state requested but light not defined\n");
2989 return WINED3DERR_INVALIDCALL;
2991 *pEnable = lightInfo->lightEnabled;
2992 return WINED3D_OK;
2995 /*****
2996 * Get / Set Clip Planes
2997 *****/
2998 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3002 /* Validate Index */
3003 if (Index >= GL_LIMITS(clipplanes)) {
3004 TRACE("Application has requested clipplane this device doesn't support\n");
3005 return WINED3DERR_INVALIDCALL;
3008 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3009 This->updateStateBlock->set.clipplane[Index] = TRUE;
3010 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3011 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3012 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3013 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3015 /* Handle recording of state blocks */
3016 if (This->isRecordingState) {
3017 TRACE("Recording... not performing anything\n");
3018 return WINED3D_OK;
3021 /* Apply it */
3023 ENTER_GL();
3025 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3026 glMatrixMode(GL_MODELVIEW);
3027 glPushMatrix();
3028 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3030 TRACE("Clipplane [%f,%f,%f,%f]\n",
3031 This->updateStateBlock->clipplane[Index][0],
3032 This->updateStateBlock->clipplane[Index][1],
3033 This->updateStateBlock->clipplane[Index][2],
3034 This->updateStateBlock->clipplane[Index][3]);
3035 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3036 checkGLcall("glClipPlane");
3038 glPopMatrix();
3039 LEAVE_GL();
3041 return WINED3D_OK;
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p) : for idx %ld\n", This, Index);
3048 /* Validate Index */
3049 if (Index >= GL_LIMITS(clipplanes)) {
3050 TRACE("Application has requested clipplane this device doesn't support\n");
3051 return WINED3DERR_INVALIDCALL;
3054 pPlane[0] = This->stateBlock->clipplane[Index][0];
3055 pPlane[1] = This->stateBlock->clipplane[Index][1];
3056 pPlane[2] = This->stateBlock->clipplane[Index][2];
3057 pPlane[3] = This->stateBlock->clipplane[Index][3];
3058 return WINED3D_OK;
3061 /*****
3062 * Get / Set Clip Plane Status
3063 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3064 *****/
3065 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 FIXME("(%p) : stub\n", This);
3068 if (NULL == pClipStatus) {
3069 return WINED3DERR_INVALIDCALL;
3071 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3072 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 FIXME("(%p) : stub\n", This);
3079 if (NULL == pClipStatus) {
3080 return WINED3DERR_INVALIDCALL;
3082 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3083 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3084 return WINED3D_OK;
3087 /*****
3088 * Get / Set Material
3089 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3090 *****/
3091 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 This->updateStateBlock->changed.material = TRUE;
3095 This->updateStateBlock->set.material = TRUE;
3096 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3098 /* Handle recording of state blocks */
3099 if (This->isRecordingState) {
3100 TRACE("Recording... not performing anything\n");
3101 return WINED3D_OK;
3104 ENTER_GL();
3105 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3106 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3107 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3108 pMaterial->Ambient.b, pMaterial->Ambient.a);
3109 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3110 pMaterial->Specular.b, pMaterial->Specular.a);
3111 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3112 pMaterial->Emissive.b, pMaterial->Emissive.a);
3113 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3115 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3116 checkGLcall("glMaterialfv(GL_AMBIENT)");
3117 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3118 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3120 /* Only change material color if specular is enabled, otherwise it is set to black */
3121 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3122 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3123 checkGLcall("glMaterialfv(GL_SPECULAR");
3124 } else {
3125 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3126 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3127 checkGLcall("glMaterialfv(GL_SPECULAR");
3129 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3130 checkGLcall("glMaterialfv(GL_EMISSION)");
3131 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3132 checkGLcall("glMaterialf(GL_SHININESS");
3134 LEAVE_GL();
3135 return WINED3D_OK;
3138 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3141 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3142 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3143 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3144 pMaterial->Ambient.b, pMaterial->Ambient.a);
3145 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3146 pMaterial->Specular.b, pMaterial->Specular.a);
3147 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3148 pMaterial->Emissive.b, pMaterial->Emissive.a);
3149 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3151 return WINED3D_OK;
3154 /*****
3155 * Get / Set Indices
3156 *****/
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3158 UINT BaseVertexIndex) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 IWineD3DIndexBuffer *oldIdxs;
3162 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3163 oldIdxs = This->updateStateBlock->pIndexData;
3165 This->updateStateBlock->changed.indices = TRUE;
3166 This->updateStateBlock->set.indices = TRUE;
3167 This->updateStateBlock->pIndexData = pIndexData;
3168 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3170 /* Handle recording of state blocks */
3171 if (This->isRecordingState) {
3172 TRACE("Recording... not performing anything\n");
3173 return WINED3D_OK;
3176 if (NULL != pIndexData) {
3177 IWineD3DIndexBuffer_AddRef(pIndexData);
3179 if (NULL != oldIdxs) {
3180 IWineD3DIndexBuffer_Release(oldIdxs);
3182 return WINED3D_OK;
3185 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 *ppIndexData = This->stateBlock->pIndexData;
3190 /* up ref count on ppindexdata */
3191 if (*ppIndexData) {
3192 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3193 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3194 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3195 }else{
3196 TRACE("(%p) No index data set\n", This);
3198 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3200 return WINED3D_OK;
3203 /*****
3204 * Get / Set Viewports
3205 *****/
3206 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 TRACE("(%p)\n", This);
3210 This->updateStateBlock->changed.viewport = TRUE;
3211 This->updateStateBlock->set.viewport = TRUE;
3212 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3214 /* Handle recording of state blocks */
3215 if (This->isRecordingState) {
3216 TRACE("Recording... not performing anything\n");
3217 return WINED3D_OK;
3219 This->viewport_changed = TRUE;
3221 ENTER_GL();
3223 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3224 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3226 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3227 checkGLcall("glDepthRange");
3228 /* Note: GL requires lower left, DirectX supplies upper left */
3229 /* TODO: replace usage of renderTarget with context management */
3230 glViewport(pViewport->X,
3231 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3232 pViewport->Width, pViewport->Height);
3234 checkGLcall("glViewport");
3236 LEAVE_GL();
3238 return WINED3D_OK;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3244 TRACE("(%p)\n", This);
3245 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3246 return WINED3D_OK;
3249 static void renderstate_stencil_twosided(
3250 IWineD3DDeviceImpl *This,
3251 GLint face,
3252 GLint func,
3253 GLint ref,
3254 GLuint mask,
3255 GLint stencilFail,
3256 GLint depthFail,
3257 GLint stencilPass ) {
3258 #if 0 /* Don't use OpenGL 2.0 calls for now */
3259 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3260 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3261 checkGLcall("glStencilFuncSeparate(...)");
3262 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3263 checkGLcall("glStencilOpSeparate(...)");
3265 else
3266 #endif
3267 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3268 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3269 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3270 GL_EXTCALL(glActiveStencilFaceEXT(face));
3271 checkGLcall("glActiveStencilFaceEXT(...)");
3272 glStencilFunc(func, ref, mask);
3273 checkGLcall("glStencilFunc(...)");
3274 glStencilOp(stencilFail, depthFail, stencilPass);
3275 checkGLcall("glStencilOp(...)");
3276 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3277 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3278 checkGLcall("glStencilFuncSeparateATI(...)");
3279 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3280 checkGLcall("glStencilOpSeparateATI(...)");
3281 } else {
3282 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3286 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3287 DWORD onesided_enable = FALSE;
3288 DWORD twosided_enable = FALSE;
3289 GLint func = GL_ALWAYS;
3290 GLint func_ccw = GL_ALWAYS;
3291 GLint ref = 0;
3292 GLuint mask = 0;
3293 GLint stencilFail = GL_KEEP;
3294 GLint depthFail = GL_KEEP;
3295 GLint stencilPass = GL_KEEP;
3296 GLint stencilFail_ccw = GL_KEEP;
3297 GLint depthFail_ccw = GL_KEEP;
3298 GLint stencilPass_ccw = GL_KEEP;
3300 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3301 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3302 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3303 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3304 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3305 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3306 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3307 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3308 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3309 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3310 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3311 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3312 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3313 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3314 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3315 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3316 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3317 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3318 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3319 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3320 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3321 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3322 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3323 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3325 switch(State) {
3326 case WINED3DRS_STENCILENABLE :
3327 onesided_enable = Value;
3328 break;
3329 case WINED3DRS_TWOSIDEDSTENCILMODE :
3330 twosided_enable = Value;
3331 break;
3332 case WINED3DRS_STENCILFUNC :
3333 func = StencilFunc(Value);
3334 break;
3335 case WINED3DRS_CCW_STENCILFUNC :
3336 func_ccw = StencilFunc(Value);
3337 break;
3338 case WINED3DRS_STENCILREF :
3339 ref = Value;
3340 break;
3341 case WINED3DRS_STENCILMASK :
3342 mask = Value;
3343 break;
3344 case WINED3DRS_STENCILFAIL :
3345 stencilFail = StencilOp(Value);
3346 break;
3347 case WINED3DRS_STENCILZFAIL :
3348 depthFail = StencilOp(Value);
3349 break;
3350 case WINED3DRS_STENCILPASS :
3351 stencilPass = StencilOp(Value);
3352 break;
3353 case WINED3DRS_CCW_STENCILFAIL :
3354 stencilFail_ccw = StencilOp(Value);
3355 break;
3356 case WINED3DRS_CCW_STENCILZFAIL :
3357 depthFail_ccw = StencilOp(Value);
3358 break;
3359 case WINED3DRS_CCW_STENCILPASS :
3360 stencilPass_ccw = StencilOp(Value);
3361 break;
3362 default :
3363 ERR("This should not happen!");
3366 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3367 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3368 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3369 onesided_enable, twosided_enable, ref, mask,
3370 func, stencilFail, depthFail, stencilPass,
3371 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3373 if (twosided_enable) {
3374 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3375 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3376 } else {
3377 if (onesided_enable) {
3378 glEnable(GL_STENCIL_TEST);
3379 checkGLcall("glEnable GL_STENCIL_TEST");
3380 glStencilFunc(func, ref, mask);
3381 checkGLcall("glStencilFunc(...)");
3382 glStencilOp(stencilFail, depthFail, stencilPass);
3383 checkGLcall("glStencilOp(...)");
3384 } else {
3385 glDisable(GL_STENCIL_TEST);
3386 checkGLcall("glDisable GL_STENCIL_TEST");
3391 /*****
3392 * Get / Set Render States
3393 * TODO: Verify against dx9 definitions
3394 *****/
3395 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 DWORD OldValue = This->stateBlock->renderState[State];
3400 /* Simple way of referring to either a DWORD or a 4 byte float */
3401 union {
3402 DWORD d;
3403 float f;
3404 } tmpvalue;
3406 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3407 This->updateStateBlock->changed.renderState[State] = TRUE;
3408 This->updateStateBlock->set.renderState[State] = TRUE;
3409 This->updateStateBlock->renderState[State] = Value;
3411 /* Handle recording of state blocks */
3412 if (This->isRecordingState) {
3413 TRACE("Recording... not performing anything\n");
3414 return WINED3D_OK;
3417 ENTER_GL();
3419 switch (State) {
3420 case WINED3DRS_FILLMODE :
3421 switch ((D3DFILLMODE) Value) {
3422 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3423 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3424 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3425 default:
3426 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3428 checkGLcall("glPolygonMode (fillmode)");
3429 break;
3431 case WINED3DRS_LIGHTING :
3432 if (Value) {
3433 glEnable(GL_LIGHTING);
3434 checkGLcall("glEnable GL_LIGHTING");
3435 } else {
3436 glDisable(GL_LIGHTING);
3437 checkGLcall("glDisable GL_LIGHTING");
3439 break;
3441 case WINED3DRS_ZENABLE :
3442 switch ((D3DZBUFFERTYPE) Value) {
3443 case D3DZB_FALSE:
3444 glDisable(GL_DEPTH_TEST);
3445 checkGLcall("glDisable GL_DEPTH_TEST");
3446 break;
3447 case D3DZB_TRUE:
3448 glEnable(GL_DEPTH_TEST);
3449 checkGLcall("glEnable GL_DEPTH_TEST");
3450 break;
3451 case D3DZB_USEW:
3452 glEnable(GL_DEPTH_TEST);
3453 checkGLcall("glEnable GL_DEPTH_TEST");
3454 FIXME("W buffer is not well handled\n");
3455 break;
3456 default:
3457 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3459 break;
3461 case WINED3DRS_CULLMODE :
3463 /* If we are culling "back faces with clockwise vertices" then
3464 set front faces to be counter clockwise and enable culling
3465 of back faces */
3466 switch ((D3DCULL) Value) {
3467 case D3DCULL_NONE:
3468 glDisable(GL_CULL_FACE);
3469 checkGLcall("glDisable GL_CULL_FACE");
3470 break;
3471 case D3DCULL_CW:
3472 glEnable(GL_CULL_FACE);
3473 checkGLcall("glEnable GL_CULL_FACE");
3474 if (This->renderUpsideDown) {
3475 glFrontFace(GL_CW);
3476 checkGLcall("glFrontFace GL_CW");
3477 } else {
3478 glFrontFace(GL_CCW);
3479 checkGLcall("glFrontFace GL_CCW");
3481 glCullFace(GL_BACK);
3482 break;
3483 case D3DCULL_CCW:
3484 glEnable(GL_CULL_FACE);
3485 checkGLcall("glEnable GL_CULL_FACE");
3486 if (This->renderUpsideDown) {
3487 glFrontFace(GL_CCW);
3488 checkGLcall("glFrontFace GL_CCW");
3489 } else {
3490 glFrontFace(GL_CW);
3491 checkGLcall("glFrontFace GL_CW");
3493 glCullFace(GL_BACK);
3494 break;
3495 default:
3496 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3498 break;
3500 case WINED3DRS_SHADEMODE :
3501 switch ((D3DSHADEMODE) Value) {
3502 case D3DSHADE_FLAT:
3503 glShadeModel(GL_FLAT);
3504 checkGLcall("glShadeModel");
3505 break;
3506 case D3DSHADE_GOURAUD:
3507 glShadeModel(GL_SMOOTH);
3508 checkGLcall("glShadeModel");
3509 break;
3510 case D3DSHADE_PHONG:
3511 FIXME("D3DSHADE_PHONG isn't supported\n");
3512 break;
3513 default:
3514 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3516 break;
3518 case WINED3DRS_DITHERENABLE :
3519 if (Value) {
3520 glEnable(GL_DITHER);
3521 checkGLcall("glEnable GL_DITHER");
3522 } else {
3523 glDisable(GL_DITHER);
3524 checkGLcall("glDisable GL_DITHER");
3526 break;
3528 case WINED3DRS_ZWRITEENABLE :
3529 if (Value) {
3530 glDepthMask(1);
3531 checkGLcall("glDepthMask");
3532 } else {
3533 glDepthMask(0);
3534 checkGLcall("glDepthMask");
3536 break;
3538 case WINED3DRS_ZFUNC :
3540 int glParm = GL_LESS;
3542 switch ((D3DCMPFUNC) Value) {
3543 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3544 case D3DCMP_LESS: glParm=GL_LESS; break;
3545 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3546 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3547 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3548 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3549 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3550 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3551 default:
3552 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3554 glDepthFunc(glParm);
3555 checkGLcall("glDepthFunc");
3557 break;
3559 case WINED3DRS_AMBIENT :
3561 float col[4];
3562 D3DCOLORTOGLFLOAT4(Value, col);
3563 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3564 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3565 checkGLcall("glLightModel for MODEL_AMBIENT");
3568 break;
3570 case WINED3DRS_ALPHABLENDENABLE :
3571 if (Value) {
3572 glEnable(GL_BLEND);
3573 checkGLcall("glEnable GL_BLEND");
3574 } else {
3575 glDisable(GL_BLEND);
3576 checkGLcall("glDisable GL_BLEND");
3578 break;
3580 case WINED3DRS_SRCBLEND :
3581 case WINED3DRS_DESTBLEND :
3583 int newVal = GL_ZERO;
3584 switch (Value) {
3585 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3586 case D3DBLEND_ONE : newVal = GL_ONE; break;
3587 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3588 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3589 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3590 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3591 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3592 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3593 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3594 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3595 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3597 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3598 This->srcBlend = newVal;
3599 This->dstBlend = newVal;
3600 break;
3602 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3603 This->srcBlend = newVal;
3604 This->dstBlend = newVal;
3605 break;
3606 default:
3607 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3610 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3611 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3612 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3613 glBlendFunc(This->srcBlend, This->dstBlend);
3615 checkGLcall("glBlendFunc");
3617 break;
3619 case WINED3DRS_ALPHATESTENABLE :
3620 case WINED3DRS_ALPHAFUNC :
3621 case WINED3DRS_ALPHAREF :
3622 case WINED3DRS_COLORKEYENABLE :
3624 int glParm = 0.0;
3625 float ref = GL_LESS;
3626 BOOL enable_ckey = FALSE;
3628 IWineD3DSurfaceImpl *surf;
3630 /* Find out if the texture on the first stage has a ckey set */
3631 if(This->stateBlock->textures[0]) {
3632 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3633 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3636 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3637 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3638 glEnable(GL_ALPHA_TEST);
3639 checkGLcall("glEnable GL_ALPHA_TEST");
3640 } else {
3641 glDisable(GL_ALPHA_TEST);
3642 checkGLcall("glDisable GL_ALPHA_TEST");
3643 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3644 * enable call
3646 break;
3649 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3650 glParm = GL_NOTEQUAL;
3651 ref = 0.0;
3652 } else {
3653 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3655 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3656 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3657 case D3DCMP_LESS: glParm = GL_LESS; break;
3658 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3659 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3660 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3661 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3662 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3663 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3664 default:
3665 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3668 This->alphafunc = glParm;
3669 glAlphaFunc(glParm, ref);
3670 checkGLcall("glAlphaFunc");
3672 break;
3674 case WINED3DRS_CLIPPLANEENABLE :
3675 case WINED3DRS_CLIPPING :
3677 /* Ensure we only do the changed clip planes */
3678 DWORD enable = 0xFFFFFFFF;
3679 DWORD disable = 0x00000000;
3681 /* If enabling / disabling all */
3682 if (State == WINED3DRS_CLIPPING) {
3683 if (Value) {
3684 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3685 disable = 0x00;
3686 } else {
3687 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3688 enable = 0x00;
3690 } else {
3691 enable = Value & ~OldValue;
3692 disable = ~Value & OldValue;
3695 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3696 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3697 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3698 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3699 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3700 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3702 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3703 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3704 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3705 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3706 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3707 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3709 /** update clipping status */
3710 if (enable) {
3711 This->stateBlock->clip_status.ClipUnion = 0;
3712 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3713 } else {
3714 This->stateBlock->clip_status.ClipUnion = 0;
3715 This->stateBlock->clip_status.ClipIntersection = 0;
3718 break;
3720 case WINED3DRS_BLENDOP :
3722 int glParm = GL_FUNC_ADD;
3724 switch ((D3DBLENDOP) Value) {
3725 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3726 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3727 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3728 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3729 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3730 default:
3731 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3734 if(GL_SUPPORT(ARB_IMAGING)) {
3735 TRACE("glBlendEquation(%x)\n", glParm);
3736 GL_EXTCALL(glBlendEquation(glParm));
3737 checkGLcall("glBlendEquation");
3738 } else {
3739 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3742 break;
3744 case WINED3DRS_TEXTUREFACTOR :
3746 unsigned int i;
3748 /* Note the texture color applies to all textures whereas
3749 GL_TEXTURE_ENV_COLOR applies to active only */
3750 float col[4];
3751 D3DCOLORTOGLFLOAT4(Value, col);
3752 /* Set the default alpha blend color */
3753 if (GL_SUPPORT(ARB_IMAGING)) {
3754 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3755 checkGLcall("glBlendColor");
3756 } else {
3757 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3760 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3761 /* And now the default texture color as well */
3762 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3763 /* Note the D3DRS value applies to all textures, but GL has one
3764 per texture, so apply it now ready to be used! */
3765 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3766 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3767 checkGLcall("glActiveTextureARB");
3768 } else if (i>0) {
3769 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3772 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3773 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3777 break;
3779 case WINED3DRS_SPECULARENABLE :
3781 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3782 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3783 specular color. This is wrong:
3784 Separate specular color means the specular colour is maintained separately, whereas
3785 single color means it is merged in. However in both cases they are being used to
3786 some extent.
3787 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3788 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3789 running 1.4 yet!
3792 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3793 * Instead, we need to setup the FinalCombiner properly.
3795 * The default setup for the FinalCombiner is:
3797 * <variable> <input> <mapping> <usage>
3798 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3799 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3800 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3801 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3802 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3803 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3804 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3806 * That's pretty much fine as it is, except for variable B, which needs to take
3807 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3808 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3811 if (Value) {
3812 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3813 checkGLcall("glMaterialfv");
3814 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3815 glEnable(GL_COLOR_SUM_EXT);
3816 } else {
3817 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3819 checkGLcall("glEnable(GL_COLOR_SUM)");
3821 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3822 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3823 checkGLcall("glFinalCombinerInputNV()");
3825 } else {
3826 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3828 /* for the case of enabled lighting: */
3829 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3830 checkGLcall("glMaterialfv");
3832 /* for the case of disabled lighting: */
3833 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3834 glDisable(GL_COLOR_SUM_EXT);
3835 } else {
3836 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3838 checkGLcall("glDisable(GL_COLOR_SUM)");
3840 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3841 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3842 checkGLcall("glFinalCombinerInputNV()");
3846 break;
3848 case WINED3DRS_STENCILENABLE :
3849 case WINED3DRS_TWOSIDEDSTENCILMODE :
3850 case WINED3DRS_STENCILFUNC :
3851 case WINED3DRS_CCW_STENCILFUNC :
3852 case WINED3DRS_STENCILREF :
3853 case WINED3DRS_STENCILMASK :
3854 case WINED3DRS_STENCILFAIL :
3855 case WINED3DRS_STENCILZFAIL :
3856 case WINED3DRS_STENCILPASS :
3857 case WINED3DRS_CCW_STENCILFAIL :
3858 case WINED3DRS_CCW_STENCILZFAIL :
3859 case WINED3DRS_CCW_STENCILPASS :
3860 renderstate_stencil(This, State, Value);
3861 break;
3862 case WINED3DRS_STENCILWRITEMASK :
3864 glStencilMask(Value);
3865 TRACE("glStencilMask(%lu)\n", Value);
3866 checkGLcall("glStencilMask");
3868 break;
3870 case WINED3DRS_FOGENABLE :
3872 if (Value) {
3873 glEnable(GL_FOG);
3874 checkGLcall("glEnable GL_FOG");
3875 } else {
3876 glDisable(GL_FOG);
3877 checkGLcall("glDisable GL_FOG");
3880 break;
3882 case WINED3DRS_RANGEFOGENABLE :
3884 if (Value) {
3885 TRACE("Enabled RANGEFOG");
3886 } else {
3887 TRACE("Disabled RANGEFOG");
3890 break;
3892 case WINED3DRS_FOGCOLOR :
3894 float col[4];
3895 D3DCOLORTOGLFLOAT4(Value, col);
3896 /* Set the default alpha blend color */
3897 glFogfv(GL_FOG_COLOR, &col[0]);
3898 checkGLcall("glFog GL_FOG_COLOR");
3900 break;
3902 case WINED3DRS_FOGTABLEMODE :
3903 case WINED3DRS_FOGVERTEXMODE :
3905 /* 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." */
3906 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3907 glHint(GL_FOG_HINT, GL_FASTEST);
3908 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3909 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3910 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3911 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3913 case D3DFOG_EXP: {
3914 if(!This->last_was_rhw) {
3915 glFogi(GL_FOG_MODE, GL_EXP);
3916 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3917 if(GL_SUPPORT(EXT_FOG_COORD)) {
3918 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3919 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3920 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3921 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3923 break;
3926 case D3DFOG_EXP2: {
3927 if(!This->last_was_rhw) {
3928 glFogi(GL_FOG_MODE, GL_EXP2);
3929 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3930 if(GL_SUPPORT(EXT_FOG_COORD)) {
3931 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3932 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3933 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3934 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3936 break;
3939 case D3DFOG_LINEAR: {
3940 if(!This->last_was_rhw) {
3941 glFogi(GL_FOG_MODE, GL_LINEAR);
3942 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3943 if(GL_SUPPORT(EXT_FOG_COORD)) {
3944 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3945 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3946 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3947 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3949 break;
3952 case D3DFOG_NONE: {
3953 /* Both are none? According to msdn the alpha channel of the specular
3954 * color contains a fog factor. Set it in drawStridedSlow.
3955 * Same happens with Vertexfog on transformed vertices
3957 if(GL_SUPPORT(EXT_FOG_COORD)) {
3958 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3959 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3960 glFogi(GL_FOG_MODE, GL_LINEAR);
3961 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3962 glFogf(GL_FOG_START, (float) 0xff);
3963 checkGLcall("glFogfv GL_FOG_START");
3964 glFogf(GL_FOG_END, 0.0);
3965 checkGLcall("glFogfv GL_FOG_END");
3966 } else {
3967 /* Disable GL fog, handle this in software in drawStridedSlow */
3968 glDisable(GL_FOG);
3969 checkGLcall("glDisable(GL_FOG)");
3971 break;
3973 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3975 } else {
3976 glHint(GL_FOG_HINT, GL_NICEST);
3977 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3978 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3979 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3980 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3981 if(GL_SUPPORT(EXT_FOG_COORD)) {
3982 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3983 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3984 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3985 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3987 break;
3988 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3989 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3990 if(GL_SUPPORT(EXT_FOG_COORD)) {
3991 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3992 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3993 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3994 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3996 break;
3997 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3998 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3999 if(GL_SUPPORT(EXT_FOG_COORD)) {
4000 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4001 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4002 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4003 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4005 break;
4006 case D3DFOG_NONE: /* Won't happen */
4007 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4010 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4011 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4014 break;
4016 case WINED3DRS_FOGSTART :
4018 tmpvalue.d = Value;
4019 glFogfv(GL_FOG_START, &tmpvalue.f);
4020 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4021 TRACE("Fog Start == %f\n", tmpvalue.f);
4023 break;
4025 case WINED3DRS_FOGEND :
4027 tmpvalue.d = Value;
4028 glFogfv(GL_FOG_END, &tmpvalue.f);
4029 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4030 TRACE("Fog End == %f\n", tmpvalue.f);
4032 break;
4034 case WINED3DRS_FOGDENSITY :
4036 tmpvalue.d = Value;
4037 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4038 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4040 break;
4042 case WINED3DRS_VERTEXBLEND :
4044 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4045 TRACE("Vertex Blending state to %ld\n", Value);
4047 break;
4049 case WINED3DRS_TWEENFACTOR :
4051 tmpvalue.d = Value;
4052 This->updateStateBlock->tween_factor = tmpvalue.f;
4053 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4055 break;
4057 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4059 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4061 break;
4063 case WINED3DRS_COLORVERTEX :
4064 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4065 case WINED3DRS_SPECULARMATERIALSOURCE :
4066 case WINED3DRS_AMBIENTMATERIALSOURCE :
4067 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4069 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4071 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4072 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4073 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4074 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4075 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4076 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4078 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4079 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4080 Parm = GL_AMBIENT_AND_DIFFUSE;
4081 } else {
4082 Parm = GL_DIFFUSE;
4084 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4085 Parm = GL_AMBIENT;
4086 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4087 Parm = GL_EMISSION;
4088 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4089 Parm = GL_SPECULAR;
4090 } else {
4091 Parm = -1;
4094 if (Parm == -1) {
4095 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4096 } else {
4097 This->tracking_color = NEEDS_TRACKING;
4098 This->tracking_parm = Parm;
4101 } else {
4102 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4105 break;
4107 case WINED3DRS_LINEPATTERN :
4109 union {
4110 DWORD d;
4111 D3DLINEPATTERN lp;
4112 } tmppattern;
4113 tmppattern.d = Value;
4115 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4117 if (tmppattern.lp.wRepeatFactor) {
4118 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4119 checkGLcall("glLineStipple(repeat, linepattern)");
4120 glEnable(GL_LINE_STIPPLE);
4121 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4122 } else {
4123 glDisable(GL_LINE_STIPPLE);
4124 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4127 break;
4129 case WINED3DRS_ZBIAS : /* D3D8 only */
4131 if (Value) {
4132 tmpvalue.d = Value;
4133 TRACE("ZBias value %f\n", tmpvalue.f);
4134 glPolygonOffset(0, -tmpvalue.f);
4135 checkGLcall("glPolygonOffset(0, -Value)");
4136 glEnable(GL_POLYGON_OFFSET_FILL);
4137 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4138 glEnable(GL_POLYGON_OFFSET_LINE);
4139 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4140 glEnable(GL_POLYGON_OFFSET_POINT);
4141 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4142 } else {
4143 glDisable(GL_POLYGON_OFFSET_FILL);
4144 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4145 glDisable(GL_POLYGON_OFFSET_LINE);
4146 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4147 glDisable(GL_POLYGON_OFFSET_POINT);
4148 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4151 break;
4153 case WINED3DRS_NORMALIZENORMALS :
4154 if (Value) {
4155 glEnable(GL_NORMALIZE);
4156 checkGLcall("glEnable(GL_NORMALIZE);");
4157 } else {
4158 glDisable(GL_NORMALIZE);
4159 checkGLcall("glDisable(GL_NORMALIZE);");
4161 break;
4163 case WINED3DRS_POINTSIZE :
4164 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4165 tmpvalue.d = Value;
4166 TRACE("Set point size to %f\n", tmpvalue.f);
4167 glPointSize(tmpvalue.f);
4168 checkGLcall("glPointSize(...);");
4169 break;
4171 case WINED3DRS_POINTSIZE_MIN :
4172 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4173 tmpvalue.d = Value;
4174 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4175 checkGLcall("glPointParameterfEXT(...);");
4176 } else {
4177 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4179 break;
4181 case WINED3DRS_POINTSIZE_MAX :
4182 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4183 tmpvalue.d = Value;
4184 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4185 checkGLcall("glPointParameterfEXT(...);");
4186 } else {
4187 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4189 break;
4191 case WINED3DRS_POINTSCALE_A :
4192 case WINED3DRS_POINTSCALE_B :
4193 case WINED3DRS_POINTSCALE_C :
4194 case WINED3DRS_POINTSCALEENABLE :
4197 * POINTSCALEENABLE controls how point size value is treated. If set to
4198 * true, the point size is scaled with respect to height of viewport.
4199 * When set to false point size is in pixels.
4201 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4204 /* Default values */
4205 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4208 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4209 * This means that OpenGL will clamp really small point sizes to 1.0f.
4210 * To correct for this we need to multiply by the scale factor when sizes
4211 * are less than 1.0f. scale_factor = 1.0f / point_size.
4213 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4214 if(pointSize > 0.0f) {
4215 GLfloat scaleFactor;
4217 if(pointSize < 1.0f) {
4218 scaleFactor = pointSize * pointSize;
4219 } else {
4220 scaleFactor = 1.0f;
4223 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4224 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4225 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4226 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4227 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4228 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4229 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4233 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4234 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4235 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4237 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4238 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4239 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4240 } else {
4241 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4243 break;
4245 case WINED3DRS_COLORWRITEENABLE :
4247 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4248 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4249 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4250 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4251 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4252 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4253 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4254 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4255 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4256 checkGLcall("glColorMask(...)");
4258 break;
4260 case WINED3DRS_LOCALVIEWER :
4262 GLint state = (Value) ? 1 : 0;
4263 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4264 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4266 break;
4268 case WINED3DRS_LASTPIXEL :
4270 if (Value) {
4271 TRACE("Last Pixel Drawing Enabled\n");
4272 } else {
4273 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4276 break;
4278 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4280 if (Value) {
4281 TRACE("Software Processing Enabled\n");
4282 } else {
4283 TRACE("Software Processing Disabled\n");
4286 break;
4288 /** not supported */
4289 case WINED3DRS_ZVISIBLE :
4291 LEAVE_GL();
4292 return WINED3DERR_INVALIDCALL;
4294 case WINED3DRS_POINTSPRITEENABLE :
4296 /* TODO: NV_POINT_SPRITE */
4297 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4298 TRACE("Point sprites not supported\n");
4299 break;
4303 * Point sprites are always enabled. Value controls texture coordinate
4304 * replacement mode. Must be set true for point sprites to use
4305 * textures.
4307 glEnable(GL_POINT_SPRITE_ARB);
4308 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4310 if (Value) {
4311 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4312 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4313 } else {
4314 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4315 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4317 break;
4319 case WINED3DRS_EDGEANTIALIAS :
4321 if(Value) {
4322 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4323 glEnable(GL_BLEND);
4324 checkGLcall("glEnable(GL_BLEND)");
4325 glEnable(GL_LINE_SMOOTH);
4326 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4327 } else {
4328 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4329 glDisable(GL_BLEND);
4330 checkGLcall("glDisable(GL_BLEND)");
4332 glDisable(GL_LINE_SMOOTH);
4333 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4335 break;
4337 case WINED3DRS_WRAP0 :
4338 case WINED3DRS_WRAP1 :
4339 case WINED3DRS_WRAP2 :
4340 case WINED3DRS_WRAP3 :
4341 case WINED3DRS_WRAP4 :
4342 case WINED3DRS_WRAP5 :
4343 case WINED3DRS_WRAP6 :
4344 case WINED3DRS_WRAP7 :
4345 case WINED3DRS_WRAP8 :
4346 case WINED3DRS_WRAP9 :
4347 case WINED3DRS_WRAP10 :
4348 case WINED3DRS_WRAP11 :
4349 case WINED3DRS_WRAP12 :
4350 case WINED3DRS_WRAP13 :
4351 case WINED3DRS_WRAP14 :
4352 case WINED3DRS_WRAP15 :
4354 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4355 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4356 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4357 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4358 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4360 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4362 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4363 break;
4364 case WINED3DRS_MULTISAMPLEANTIALIAS :
4366 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4367 TRACE("Multisample antialiasing not supported\n");
4368 break;
4371 if(Value) {
4372 glEnable(GL_MULTISAMPLE_ARB);
4373 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4374 } else {
4375 glDisable(GL_MULTISAMPLE_ARB);
4376 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4378 break;
4380 case WINED3DRS_SCISSORTESTENABLE :
4382 if(Value) {
4383 glEnable(GL_SCISSOR_TEST);
4384 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4385 } else {
4386 glDisable(GL_SCISSOR_TEST);
4387 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4389 break;
4391 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4393 if(Value) {
4394 tmpvalue.d = Value;
4395 glEnable(GL_POLYGON_OFFSET_FILL);
4396 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4397 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4398 checkGLcall("glPolygonOffset(...)");
4399 } else {
4400 glDisable(GL_POLYGON_OFFSET_FILL);
4401 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4403 break;
4405 case WINED3DRS_ANTIALIASEDLINEENABLE :
4407 if(Value) {
4408 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4409 glEnable(GL_BLEND);
4410 checkGLcall("glEnable(GL_BLEND)");
4411 glEnable(GL_LINE_SMOOTH);
4412 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4413 } else {
4414 glDisable(GL_BLEND);
4415 checkGLcall("glDisable(GL_BLEND)");
4416 glDisable(GL_LINE_SMOOTH);
4417 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4419 break;
4421 case WINED3DRS_DEPTHBIAS :
4423 if(Value) {
4424 tmpvalue.d = Value;
4425 glEnable(GL_POLYGON_OFFSET_FILL);
4426 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4427 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4428 checkGLcall("glPolygonOffset(...)");
4429 } else {
4430 glDisable(GL_POLYGON_OFFSET_FILL);
4431 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4433 break;
4436 case WINED3DRS_TEXTUREPERSPECTIVE :
4438 if (Value)
4439 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4440 else
4441 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4442 break;
4445 case WINED3DRS_STIPPLEDALPHA :
4447 if (Value)
4448 ERR(" Stippled Alpha not supported yet.\n");
4449 break;
4451 case WINED3DRS_ANTIALIAS :
4453 if (Value)
4454 ERR(" Antialias not supported yet.\n");
4455 break;
4457 default:
4458 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4461 LEAVE_GL();
4463 return WINED3D_OK;
4466 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4468 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4469 *pValue = This->stateBlock->renderState[State];
4470 return WINED3D_OK;
4473 /*****
4474 * Get / Set Sampler States
4475 * TODO: Verify against dx9 definitions
4476 *****/
4478 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4481 * SetSampler is designed to allow for more than the standard up to 8 textures
4482 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4483 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4485 * http://developer.nvidia.com/object/General_FAQ.html#t6
4487 * There are two new settings for GForce
4488 * the sampler one:
4489 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4490 * and the texture one:
4491 * GL_MAX_TEXTURE_COORDS_ARB.
4492 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4493 ******************/
4494 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4495 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4496 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4497 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4498 return WINED3DERR_INVALIDCALL;
4501 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4502 debug_d3dsamplerstate(Type), Type, Value);
4503 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4504 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4505 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4507 /* Handle recording of state blocks */
4508 if (This->isRecordingState) {
4509 TRACE("Recording... not performing anything\n");
4510 return WINED3D_OK;
4513 return WINED3D_OK;
4516 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 /** TODO: check that sampler is in range **/
4519 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4520 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4522 return WINED3D_OK;
4525 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 ENTER_GL();
4529 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4530 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4531 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4532 LEAVE_GL();
4534 return WINED3D_OK;
4537 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4539 GLint scissorBox[4];
4541 ENTER_GL();
4542 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4543 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4544 pRect->left = scissorBox[0];
4545 pRect->top = scissorBox[1];
4546 pRect->right = scissorBox[0] + scissorBox[2];
4547 pRect->bottom = scissorBox[1] + scissorBox[3];
4548 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4549 LEAVE_GL();
4550 return WINED3D_OK;
4553 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4555 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4557 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4559 This->updateStateBlock->vertexDecl = pDecl;
4560 This->updateStateBlock->changed.vertexDecl = TRUE;
4561 This->updateStateBlock->set.vertexDecl = TRUE;
4563 if (This->isRecordingState) {
4564 TRACE("Recording... not performing anything\n");
4567 if (NULL != pDecl) {
4568 IWineD3DVertexDeclaration_AddRef(pDecl);
4570 if (NULL != oldDecl) {
4571 IWineD3DVertexDeclaration_Release(oldDecl);
4573 return WINED3D_OK;
4576 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4581 *ppDecl = This->stateBlock->vertexDecl;
4582 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4583 return WINED3D_OK;
4586 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4590 This->updateStateBlock->vertexShader = pShader;
4591 This->updateStateBlock->changed.vertexShader = TRUE;
4592 This->updateStateBlock->set.vertexShader = TRUE;
4594 if (This->isRecordingState) {
4595 TRACE("Recording... not performing anything\n");
4598 if (NULL != pShader) {
4599 IWineD3DVertexShader_AddRef(pShader);
4601 if (NULL != oldShader) {
4602 IWineD3DVertexShader_Release(oldShader);
4605 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4607 * TODO: merge HAL shaders context switching from prototype
4609 return WINED3D_OK;
4612 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4615 if (NULL == ppShader) {
4616 return WINED3DERR_INVALIDCALL;
4618 *ppShader = This->stateBlock->vertexShader;
4619 if( NULL != *ppShader)
4620 IWineD3DVertexShader_AddRef(*ppShader);
4622 TRACE("(%p) : returning %p\n", This, *ppShader);
4623 return WINED3D_OK;
4626 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4627 IWineD3DDevice *iface,
4628 UINT start,
4629 CONST BOOL *srcData,
4630 UINT count) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 int i, cnt = min(count, MAX_CONST_B - start);
4635 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4636 iface, srcData, start, count);
4638 if (srcData == NULL || cnt < 0)
4639 return WINED3DERR_INVALIDCALL;
4641 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4642 for (i = 0; i < cnt; i++)
4643 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4645 for (i = start; i < cnt + start; ++i) {
4646 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4647 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4650 return WINED3D_OK;
4653 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4654 IWineD3DDevice *iface,
4655 UINT start,
4656 BOOL *dstData,
4657 UINT count) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 int cnt = min(count, MAX_CONST_B - start);
4662 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4663 iface, dstData, start, count);
4665 if (dstData == NULL || cnt < 0)
4666 return WINED3DERR_INVALIDCALL;
4668 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4669 return WINED3D_OK;
4672 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4673 IWineD3DDevice *iface,
4674 UINT start,
4675 CONST int *srcData,
4676 UINT count) {
4678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4679 int i, cnt = min(count, MAX_CONST_I - start);
4681 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4682 iface, srcData, start, count);
4684 if (srcData == NULL || cnt < 0)
4685 return WINED3DERR_INVALIDCALL;
4687 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4688 for (i = 0; i < cnt; i++)
4689 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4690 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4692 for (i = start; i < cnt + start; ++i) {
4693 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4694 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4697 return WINED3D_OK;
4700 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4701 IWineD3DDevice *iface,
4702 UINT start,
4703 int *dstData,
4704 UINT count) {
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 int cnt = min(count, MAX_CONST_I - start);
4709 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4710 iface, dstData, start, count);
4712 if (dstData == NULL || cnt < 0)
4713 return WINED3DERR_INVALIDCALL;
4715 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4716 return WINED3D_OK;
4719 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4720 IWineD3DDevice *iface,
4721 UINT start,
4722 CONST float *srcData,
4723 UINT count) {
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4726 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4728 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4729 iface, srcData, start, count);
4731 if (srcData == NULL || cnt < 0)
4732 return WINED3DERR_INVALIDCALL;
4734 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4735 for (i = 0; i < cnt; i++)
4736 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4737 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4739 for (i = start; i < cnt + start; ++i) {
4740 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4741 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4744 return WINED3D_OK;
4747 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4748 IWineD3DDevice *iface,
4749 UINT start,
4750 float *dstData,
4751 UINT count) {
4753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4754 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4756 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4757 iface, dstData, start, count);
4759 if (dstData == NULL || cnt < 0)
4760 return WINED3DERR_INVALIDCALL;
4762 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4763 return WINED3D_OK;
4766 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4769 This->updateStateBlock->pixelShader = pShader;
4770 This->updateStateBlock->changed.pixelShader = TRUE;
4771 This->updateStateBlock->set.pixelShader = TRUE;
4773 /* Handle recording of state blocks */
4774 if (This->isRecordingState) {
4775 TRACE("Recording... not performing anything\n");
4778 if (NULL != pShader) {
4779 IWineD3DPixelShader_AddRef(pShader);
4781 if (NULL != oldShader) {
4782 IWineD3DPixelShader_Release(oldShader);
4785 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4787 * TODO: merge HAL shaders context switching from prototype
4789 return WINED3D_OK;
4792 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4795 if (NULL == ppShader) {
4796 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4797 return WINED3DERR_INVALIDCALL;
4800 *ppShader = This->stateBlock->pixelShader;
4801 if (NULL != *ppShader) {
4802 IWineD3DPixelShader_AddRef(*ppShader);
4804 TRACE("(%p) : returning %p\n", This, *ppShader);
4805 return WINED3D_OK;
4808 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4809 IWineD3DDevice *iface,
4810 UINT start,
4811 CONST BOOL *srcData,
4812 UINT count) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 int i, cnt = min(count, MAX_CONST_B - start);
4817 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4818 iface, srcData, start, count);
4820 if (srcData == NULL || cnt < 0)
4821 return WINED3DERR_INVALIDCALL;
4823 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4824 for (i = 0; i < cnt; i++)
4825 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4827 for (i = start; i < cnt + start; ++i) {
4828 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4829 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4832 return WINED3D_OK;
4835 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4836 IWineD3DDevice *iface,
4837 UINT start,
4838 BOOL *dstData,
4839 UINT count) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 int cnt = min(count, MAX_CONST_B - start);
4844 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4845 iface, dstData, start, count);
4847 if (dstData == NULL || cnt < 0)
4848 return WINED3DERR_INVALIDCALL;
4850 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4851 return WINED3D_OK;
4854 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4855 IWineD3DDevice *iface,
4856 UINT start,
4857 CONST int *srcData,
4858 UINT count) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4861 int i, cnt = min(count, MAX_CONST_I - start);
4863 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4864 iface, srcData, start, count);
4866 if (srcData == NULL || cnt < 0)
4867 return WINED3DERR_INVALIDCALL;
4869 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4870 for (i = 0; i < cnt; i++)
4871 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4872 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4874 for (i = start; i < cnt + start; ++i) {
4875 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4876 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4879 return WINED3D_OK;
4882 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4883 IWineD3DDevice *iface,
4884 UINT start,
4885 int *dstData,
4886 UINT count) {
4888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4889 int cnt = min(count, MAX_CONST_I - start);
4891 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4892 iface, dstData, start, count);
4894 if (dstData == NULL || cnt < 0)
4895 return WINED3DERR_INVALIDCALL;
4897 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4898 return WINED3D_OK;
4901 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4902 IWineD3DDevice *iface,
4903 UINT start,
4904 CONST float *srcData,
4905 UINT count) {
4907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4908 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4910 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4911 iface, srcData, start, count);
4913 if (srcData == NULL || cnt < 0)
4914 return WINED3DERR_INVALIDCALL;
4916 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4917 for (i = 0; i < cnt; i++)
4918 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4919 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4921 for (i = start; i < cnt + start; ++i) {
4922 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4923 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4926 return WINED3D_OK;
4929 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4930 IWineD3DDevice *iface,
4931 UINT start,
4932 float *dstData,
4933 UINT count) {
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4936 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4938 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4939 iface, dstData, start, count);
4941 if (dstData == NULL || cnt < 0)
4942 return WINED3DERR_INVALIDCALL;
4944 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4945 return WINED3D_OK;
4948 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4949 static HRESULT
4950 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4951 char *dest_ptr, *dest_conv = NULL;
4952 unsigned int i;
4953 DWORD DestFVF = dest->fvf;
4954 D3DVIEWPORT9 vp;
4955 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4956 BOOL doClip;
4957 int numTextures;
4959 if (SrcFVF & D3DFVF_NORMAL) {
4960 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4963 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4964 ERR("Source has no position mask\n");
4965 return WINED3DERR_INVALIDCALL;
4968 /* We might access VBOs from this code, so hold the lock */
4969 ENTER_GL();
4971 if (dest->resource.allocatedMemory == NULL) {
4972 /* This may happen if we do direct locking into a vbo. Unlikely,
4973 * but theoretically possible(ddraw processvertices test)
4975 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4976 if(!dest->resource.allocatedMemory) {
4977 LEAVE_GL();
4978 ERR("Out of memory\n");
4979 return E_OUTOFMEMORY;
4981 if(dest->vbo) {
4982 void *src;
4983 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4984 checkGLcall("glBindBufferARB");
4985 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4986 if(src) {
4987 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4989 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4990 checkGLcall("glUnmapBufferARB");
4994 /* Get a pointer into the destination vbo(create one if none exists) and
4995 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4997 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4998 CreateVBO(dest);
5001 if(dest->vbo) {
5002 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5003 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5004 if(!dest_conv) {
5005 ERR("glMapBuffer failed\n");
5006 /* Continue without storing converted vertices */
5010 /* Should I clip?
5011 * a) D3DRS_CLIPPING is enabled
5012 * b) WINED3DVOP_CLIP is passed
5014 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5015 static BOOL warned = FALSE;
5017 * The clipping code is not quite correct. Some things need
5018 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5019 * so disable clipping for now.
5020 * (The graphics in Half-Life are broken, and my processvertices
5021 * test crashes with IDirect3DDevice3)
5022 doClip = TRUE;
5024 doClip = FALSE;
5025 if(!warned) {
5026 warned = TRUE;
5027 FIXME("Clipping is broken and disabled for now\n");
5029 } else doClip = FALSE;
5030 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5031 if(dest_conv) {
5032 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5035 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5036 WINED3DTS_VIEW,
5037 &view_mat);
5038 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5039 WINED3DTS_PROJECTION,
5040 &proj_mat);
5041 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5042 WINED3DTS_WORLDMATRIX(0),
5043 &world_mat);
5045 TRACE("View mat:\n");
5046 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); \
5047 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); \
5048 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); \
5049 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); \
5051 TRACE("Proj mat:\n");
5052 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); \
5053 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); \
5054 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); \
5055 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); \
5057 TRACE("World mat:\n");
5058 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); \
5059 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); \
5060 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); \
5061 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); \
5063 /* Get the viewport */
5064 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5065 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5066 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5068 multiply_matrix(&mat,&view_mat,&world_mat);
5069 multiply_matrix(&mat,&proj_mat,&mat);
5071 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5073 for (i = 0; i < dwCount; i+= 1) {
5074 unsigned int tex_index;
5076 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5077 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5078 /* The position first */
5079 float *p =
5080 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5081 float x, y, z, rhw;
5082 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5084 /* Multiplication with world, view and projection matrix */
5085 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);
5086 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);
5087 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);
5088 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);
5090 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5092 /* WARNING: The following things are taken from d3d7 and were not yet checked
5093 * against d3d8 or d3d9!
5096 /* Clipping conditions: From
5097 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5099 * A vertex is clipped if it does not match the following requirements
5100 * -rhw < x <= rhw
5101 * -rhw < y <= rhw
5102 * 0 < z <= rhw
5103 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5105 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5106 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5110 if( doClip == FALSE ||
5111 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5112 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5113 ( rhw > eps ) ) ) {
5115 /* "Normal" viewport transformation (not clipped)
5116 * 1) The values are divided by rhw
5117 * 2) The y axis is negative, so multiply it with -1
5118 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5119 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5120 * 4) Multiply x with Width/2 and add Width/2
5121 * 5) The same for the height
5122 * 6) Add the viewpoint X and Y to the 2D coordinates and
5123 * The minimum Z value to z
5124 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5126 * Well, basically it's simply a linear transformation into viewport
5127 * coordinates
5130 x /= rhw;
5131 y /= rhw;
5132 z /= rhw;
5134 y *= -1;
5136 x *= vp.Width / 2;
5137 y *= vp.Height / 2;
5138 z *= vp.MaxZ - vp.MinZ;
5140 x += vp.Width / 2 + vp.X;
5141 y += vp.Height / 2 + vp.Y;
5142 z += vp.MinZ;
5144 rhw = 1 / rhw;
5145 } else {
5146 /* That vertex got clipped
5147 * Contrary to OpenGL it is not dropped completely, it just
5148 * undergoes a different calculation.
5150 TRACE("Vertex got clipped\n");
5151 x += rhw;
5152 y += rhw;
5154 x /= 2;
5155 y /= 2;
5157 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5158 * outside of the main vertex buffer memory. That needs some more
5159 * investigation...
5163 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5166 ( (float *) dest_ptr)[0] = x;
5167 ( (float *) dest_ptr)[1] = y;
5168 ( (float *) dest_ptr)[2] = z;
5169 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5171 dest_ptr += 3 * sizeof(float);
5173 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5174 dest_ptr += sizeof(float);
5177 if(dest_conv) {
5178 float w = 1 / rhw;
5179 ( (float *) dest_conv)[0] = x * w;
5180 ( (float *) dest_conv)[1] = y * w;
5181 ( (float *) dest_conv)[2] = z * w;
5182 ( (float *) dest_conv)[3] = w;
5184 dest_conv += 3 * sizeof(float);
5186 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5187 dest_conv += sizeof(float);
5191 if (DestFVF & D3DFVF_PSIZE) {
5192 dest_ptr += sizeof(DWORD);
5193 if(dest_conv) dest_conv += sizeof(DWORD);
5195 if (DestFVF & D3DFVF_NORMAL) {
5196 float *normal =
5197 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5198 /* AFAIK this should go into the lighting information */
5199 FIXME("Didn't expect the destination to have a normal\n");
5200 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5201 if(dest_conv) {
5202 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5206 if (DestFVF & D3DFVF_DIFFUSE) {
5207 DWORD *color_d =
5208 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5209 if(!color_d) {
5210 static BOOL warned = FALSE;
5212 if(warned == FALSE) {
5213 ERR("No diffuse color in source, but destination has one\n");
5214 warned = TRUE;
5217 *( (DWORD *) dest_ptr) = 0xffffffff;
5218 dest_ptr += sizeof(DWORD);
5220 if(dest_conv) {
5221 *( (DWORD *) dest_conv) = 0xffffffff;
5222 dest_conv += sizeof(DWORD);
5225 else {
5226 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5227 if(dest_conv) {
5228 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5229 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5230 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5231 dest_conv += sizeof(DWORD);
5236 if (DestFVF & D3DFVF_SPECULAR) {
5237 /* What's the color value in the feedback buffer? */
5238 DWORD *color_s =
5239 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5240 if(!color_s) {
5241 static BOOL warned = FALSE;
5243 if(warned == FALSE) {
5244 ERR("No specular color in source, but destination has one\n");
5245 warned = TRUE;
5248 *( (DWORD *) dest_ptr) = 0xFF000000;
5249 dest_ptr += sizeof(DWORD);
5251 if(dest_conv) {
5252 *( (DWORD *) dest_conv) = 0xFF000000;
5253 dest_conv += sizeof(DWORD);
5256 else {
5257 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5258 if(dest_conv) {
5259 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5260 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5261 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5262 dest_conv += sizeof(DWORD);
5267 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5268 float *tex_coord =
5269 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5270 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5271 if(!tex_coord) {
5272 ERR("No source texture, but destination requests one\n");
5273 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5274 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5276 else {
5277 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5278 if(dest_conv) {
5279 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5285 if(dest_conv) {
5286 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5287 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5290 LEAVE_GL();
5292 return WINED3D_OK;
5294 #undef copy_and_next
5296 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5298 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5299 WineDirect3DVertexStridedData strided;
5300 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5302 /* We don't need the source vbo because this buffer is only used as
5303 * a source for ProcessVertices. Avoid wasting resources by converting the
5304 * buffer and loading the VBO
5306 if(SrcImpl->vbo) {
5307 TRACE("Releaseing the source vbo, it won't be needed\n");
5309 if(!SrcImpl->resource.allocatedMemory) {
5310 /* Rescue the data from the buffer */
5311 void *src;
5312 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5313 if(!SrcImpl->resource.allocatedMemory) {
5314 ERR("Out of memory\n");
5315 return E_OUTOFMEMORY;
5318 ENTER_GL();
5319 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5320 checkGLcall("glBindBufferARB");
5322 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5323 if(src) {
5324 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5327 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5328 checkGLcall("glUnmapBufferARB");
5329 } else {
5330 ENTER_GL();
5333 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5334 checkGLcall("glBindBufferARB");
5335 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5336 checkGLcall("glDeleteBuffersARB");
5337 LEAVE_GL();
5339 SrcImpl->vbo = 0;
5342 memset(&strided, 0, sizeof(strided));
5343 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5345 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5348 /*****
5349 * Apply / Get / Set Texture Stage States
5350 * TODO: Verify against dx9 definitions
5351 *****/
5353 /* 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 */
5354 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5356 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5357 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5359 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5361 /* Check that the stage is within limits */
5362 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5363 TRACE("Attempt to access invalid texture rejected\n");
5364 return;
5367 ENTER_GL();
5369 switch (Type) {
5370 case WINED3DTSS_ALPHAOP :
5371 case WINED3DTSS_COLOROP :
5372 /* nothing to do as moved to drawprim for now */
5373 break;
5374 case WINED3DTSS_ADDRESSW :
5375 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5376 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5377 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5379 } else {
5380 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5381 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5382 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5383 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5385 #endif
5386 case WINED3DTSS_TEXCOORDINDEX :
5388 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5390 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5391 one flag, you can still specify an index value, which the system uses to
5392 determine the texture wrapping mode.
5393 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5394 means use the vertex position (camera-space) as the input texture coordinates
5395 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5396 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5397 to the TEXCOORDINDEX value */
5400 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5402 switch (Value & 0xFFFF0000) {
5403 case D3DTSS_TCI_PASSTHRU:
5404 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5405 glDisable(GL_TEXTURE_GEN_S);
5406 glDisable(GL_TEXTURE_GEN_T);
5407 glDisable(GL_TEXTURE_GEN_R);
5408 glDisable(GL_TEXTURE_GEN_Q);
5409 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5410 break;
5412 case D3DTSS_TCI_CAMERASPACEPOSITION:
5413 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5414 as the input texture coordinates for this stage's texture transformation. This
5415 equates roughly to EYE_LINEAR */
5417 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5418 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5419 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5420 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5421 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5423 glMatrixMode(GL_MODELVIEW);
5424 glPushMatrix();
5425 glLoadIdentity();
5426 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5427 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5428 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5429 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5430 glPopMatrix();
5432 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5433 glEnable(GL_TEXTURE_GEN_S);
5434 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5435 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5436 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5437 glEnable(GL_TEXTURE_GEN_T);
5438 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5439 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5440 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5441 glEnable(GL_TEXTURE_GEN_R);
5442 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5443 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5444 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5446 break;
5448 case D3DTSS_TCI_CAMERASPACENORMAL:
5450 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5451 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5452 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5453 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5454 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5455 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5457 glMatrixMode(GL_MODELVIEW);
5458 glPushMatrix();
5459 glLoadIdentity();
5460 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5461 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5462 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5463 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5464 glPopMatrix();
5466 glEnable(GL_TEXTURE_GEN_S);
5467 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5468 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5469 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5470 glEnable(GL_TEXTURE_GEN_T);
5471 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5472 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5473 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5474 glEnable(GL_TEXTURE_GEN_R);
5475 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5476 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5477 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5480 break;
5482 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5484 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5485 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5486 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5487 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5488 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5489 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5491 glMatrixMode(GL_MODELVIEW);
5492 glPushMatrix();
5493 glLoadIdentity();
5494 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5495 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5496 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5497 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5498 glPopMatrix();
5500 glEnable(GL_TEXTURE_GEN_S);
5501 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5502 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5503 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5504 glEnable(GL_TEXTURE_GEN_T);
5505 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5506 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5507 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5508 glEnable(GL_TEXTURE_GEN_R);
5509 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5510 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5511 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5514 break;
5516 /* Unhandled types: */
5517 default:
5518 /* Todo: */
5519 /* ? disable GL_TEXTURE_GEN_n ? */
5520 glDisable(GL_TEXTURE_GEN_S);
5521 glDisable(GL_TEXTURE_GEN_T);
5522 glDisable(GL_TEXTURE_GEN_R);
5523 glDisable(GL_TEXTURE_GEN_Q);
5524 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5525 break;
5528 break;
5530 /* Unhandled */
5531 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5532 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);
5533 break;
5535 case WINED3DTSS_BUMPENVMAT00 :
5536 case WINED3DTSS_BUMPENVMAT01 :
5537 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5538 break;
5539 case WINED3DTSS_BUMPENVMAT10 :
5540 case WINED3DTSS_BUMPENVMAT11 :
5541 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5542 break;
5544 case WINED3DTSS_BUMPENVLSCALE :
5545 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5546 break;
5548 case WINED3DTSS_BUMPENVLOFFSET :
5549 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5550 break;
5552 case WINED3DTSS_RESULTARG :
5553 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5554 break;
5556 default:
5557 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5558 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5561 LEAVE_GL();
5563 return;
5566 /*****
5567 * Get / Set Texture Stage States
5568 * TODO: Verify against dx9 definitions
5569 *****/
5570 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5575 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5577 /* Reject invalid texture units */
5578 if (Stage >= GL_LIMITS(texture_stages)) {
5579 TRACE("Attempt to access invalid texture rejected\n");
5580 return WINED3DERR_INVALIDCALL;
5583 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5584 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5585 This->updateStateBlock->textureState[Stage][Type] = Value;
5587 return WINED3D_OK;
5590 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5592 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5593 *pValue = This->updateStateBlock->textureState[Stage][Type];
5594 return WINED3D_OK;
5597 /*****
5598 * Get / Set Texture
5599 *****/
5600 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 IWineD3DBaseTexture *oldTexture;
5605 oldTexture = This->updateStateBlock->textures[Stage];
5606 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5608 #if 0 /* TODO: check so vertex textures */
5609 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5610 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5611 return WINED3D_OK;
5613 #endif
5615 /* Reject invalid texture units */
5616 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5617 WARN("Attempt to access invalid texture rejected\n");
5618 return WINED3DERR_INVALIDCALL;
5621 if(pTexture != NULL) {
5622 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5624 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5625 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5626 return WINED3DERR_INVALIDCALL;
5630 oldTexture = This->updateStateBlock->textures[Stage];
5631 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5632 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5634 This->updateStateBlock->set.textures[Stage] = TRUE;
5635 This->updateStateBlock->changed.textures[Stage] = TRUE;
5636 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5637 This->updateStateBlock->textures[Stage] = pTexture;
5639 /* Handle recording of state blocks */
5640 if (This->isRecordingState) {
5641 TRACE("Recording... not performing anything\n");
5642 return WINED3D_OK;
5645 /** NOTE: MSDN says that setTexture increases the reference count,
5646 * and the the application nust set the texture back to null (or have a leaky application),
5647 * This means we should pass the refcount up to the parent
5648 *******************************/
5649 if (NULL != This->updateStateBlock->textures[Stage]) {
5650 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5653 if (NULL != oldTexture) {
5654 IWineD3DBaseTexture_Release(oldTexture);
5657 /* Reset color keying */
5658 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5659 BOOL enable_ckey = FALSE;
5661 if(pTexture) {
5662 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5663 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5666 if(enable_ckey) {
5667 glAlphaFunc(GL_NOTEQUAL, 0.0);
5668 checkGLcall("glAlphaFunc");
5672 return WINED3D_OK;
5675 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5677 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5679 /* Reject invalid texture units */
5680 if (Stage >= GL_LIMITS(sampler_stages)) {
5681 TRACE("Attempt to access invalid texture rejected\n");
5682 return WINED3DERR_INVALIDCALL;
5684 *ppTexture=This->updateStateBlock->textures[Stage];
5685 if (*ppTexture)
5686 IWineD3DBaseTexture_AddRef(*ppTexture);
5687 else
5688 return WINED3DERR_INVALIDCALL;
5689 return WINED3D_OK;
5692 /*****
5693 * Get Back Buffer
5694 *****/
5695 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5696 IWineD3DSurface **ppBackBuffer) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 IWineD3DSwapChain *swapChain;
5699 HRESULT hr;
5701 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5703 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5704 if (hr == WINED3D_OK) {
5705 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5706 IWineD3DSwapChain_Release(swapChain);
5707 } else {
5708 *ppBackBuffer = NULL;
5710 return hr;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5715 WARN("(%p) : stub, calling idirect3d for now\n", This);
5716 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5719 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5721 IWineD3DSwapChain *swapChain;
5722 HRESULT hr;
5724 if(iSwapChain > 0) {
5725 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5726 if (hr == WINED3D_OK) {
5727 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5728 IWineD3DSwapChain_Release(swapChain);
5729 } else {
5730 FIXME("(%p) Error getting display mode\n", This);
5732 } else {
5733 /* Don't read the real display mode,
5734 but return the stored mode instead. X11 can't change the color
5735 depth, and some apps are pretty angry if they SetDisplayMode from
5736 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5738 Also don't relay to the swapchain because with ddraw it's possible
5739 that there isn't a swapchain at all */
5740 pMode->Width = This->ddraw_width;
5741 pMode->Height = This->ddraw_height;
5742 pMode->Format = This->ddraw_format;
5743 pMode->RefreshRate = 0;
5744 hr = WINED3D_OK;
5747 return hr;
5750 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 TRACE("(%p)->(%p)\n", This, hWnd);
5754 This->ddraw_window = hWnd;
5755 return WINED3D_OK;
5758 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5760 TRACE("(%p)->(%p)\n", This, hWnd);
5762 *hWnd = This->ddraw_window;
5763 return WINED3D_OK;
5766 /*****
5767 * Stateblock related functions
5768 *****/
5770 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 IWineD3DStateBlockImpl *object;
5773 HRESULT temp_result;
5775 TRACE("(%p)", This);
5777 if (This->isRecordingState) {
5778 return WINED3DERR_INVALIDCALL;
5781 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5782 if (NULL == object ) {
5783 FIXME("(%p)Error allocating memory for stateblock\n", This);
5784 return E_OUTOFMEMORY;
5786 TRACE("(%p) created object %p\n", This, object);
5787 object->wineD3DDevice= This;
5788 /** FIXME: object->parent = parent; **/
5789 object->parent = NULL;
5790 object->blockType = WINED3DSBT_ALL;
5791 object->ref = 1;
5792 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5794 temp_result = allocate_shader_constants(object);
5795 if (WINED3D_OK != temp_result)
5796 return temp_result;
5798 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5799 This->updateStateBlock = object;
5800 This->isRecordingState = TRUE;
5802 TRACE("(%p) recording stateblock %p\n",This , object);
5803 return WINED3D_OK;
5806 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5809 if (!This->isRecordingState) {
5810 FIXME("(%p) not recording! returning error\n", This);
5811 *ppStateBlock = NULL;
5812 return WINED3DERR_INVALIDCALL;
5815 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5816 This->isRecordingState = FALSE;
5817 This->updateStateBlock = This->stateBlock;
5818 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5819 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5820 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5821 return WINED3D_OK;
5824 /*****
5825 * Scene related functions
5826 *****/
5827 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5828 /* At the moment we have no need for any functionality at the beginning
5829 of a scene */
5830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5831 TRACE("(%p) : stub\n", This);
5832 return WINED3D_OK;
5835 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5837 TRACE("(%p)\n", This);
5838 ENTER_GL();
5839 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5840 glFlush();
5841 checkGLcall("glFlush");
5843 TRACE("End Scene\n");
5844 if(This->renderTarget != NULL) {
5846 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5847 IUnknown *targetContainer = NULL;
5848 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5849 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5850 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5851 /** always dirtify for now. we must find a better way to see that surface have been modified
5852 (Modifications should will only occur via draw-primitive, but we do need better locking
5853 switching to render-to-texture should remove the overhead though.
5855 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5856 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5857 IWineD3DSurface_PreLoad(This->renderTarget);
5858 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5859 IUnknown_Release(targetContainer);
5862 This->sceneEnded = TRUE;
5863 LEAVE_GL();
5864 return WINED3D_OK;
5867 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5868 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5869 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5871 IWineD3DSwapChain *swapChain = NULL;
5872 int i;
5873 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5875 TRACE("(%p) Presenting the frame\n", This);
5877 for(i = 0 ; i < swapchains ; i ++) {
5879 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5880 TRACE("presentinng chain %d, %p\n", i, swapChain);
5881 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5882 IWineD3DSwapChain_Release(swapChain);
5885 return WINED3D_OK;
5888 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5889 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5892 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5893 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5894 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5895 GLbitfield glMask = 0;
5896 GLboolean old_ztest;
5897 GLfloat old_z_clear_value;
5898 GLint old_stencil_clear_value;
5899 GLfloat old_color_clear_value[4];
5900 unsigned int i;
5901 CONST D3DRECT* curRect;
5903 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5904 Count, pRects, Flags, Z, Stencil);
5906 ENTER_GL();
5908 glEnable(GL_SCISSOR_TEST);
5909 checkGLcall("glEnable GL_SCISSOR_TEST");
5911 if (Count > 0 && pRects) {
5912 curRect = pRects;
5913 } else {
5914 curRect = NULL;
5917 /* Only set the values up once, as they are not changing */
5918 if (Flags & D3DCLEAR_STENCIL) {
5919 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5920 glClearStencil(Stencil);
5921 checkGLcall("glClearStencil");
5922 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5923 glStencilMask(0xFFFFFFFF);
5926 if (Flags & D3DCLEAR_ZBUFFER) {
5927 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5928 glDepthMask(GL_TRUE);
5929 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5930 glClearDepth(Z);
5931 checkGLcall("glClearDepth");
5932 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5935 if (Flags & D3DCLEAR_TARGET) {
5936 TRACE("Clearing screen with glClear to color %lx\n", Color);
5937 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5938 glClearColor(D3DCOLOR_R(Color),
5939 D3DCOLOR_G(Color),
5940 D3DCOLOR_B(Color),
5941 D3DCOLOR_A(Color));
5942 checkGLcall("glClearColor");
5944 /* Clear ALL colors! */
5945 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5946 glMask = glMask | GL_COLOR_BUFFER_BIT;
5949 /* Now process each rect in turn */
5950 for (i = 0; i < Count || i == 0; i++) {
5952 if (curRect) {
5953 /* Note gl uses lower left, width/height */
5954 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5955 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5956 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5957 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5958 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5959 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5960 checkGLcall("glScissor");
5961 } else {
5962 glScissor(This->stateBlock->viewport.X,
5963 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5964 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5965 This->stateBlock->viewport.Width,
5966 This->stateBlock->viewport.Height);
5967 checkGLcall("glScissor");
5970 /* Clear the selected rectangle (or full screen) */
5971 glClear(glMask);
5972 checkGLcall("glClear");
5974 /* Step to the next rectangle */
5975 if (curRect) curRect = curRect + sizeof(D3DRECT);
5978 /* Restore the old values (why..?) */
5979 if (Flags & D3DCLEAR_STENCIL) {
5980 glClearStencil(old_stencil_clear_value);
5981 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5983 if (Flags & D3DCLEAR_ZBUFFER) {
5984 glDepthMask(old_ztest);
5985 glClearDepth(old_z_clear_value);
5987 if (Flags & D3DCLEAR_TARGET) {
5988 glClearColor(old_color_clear_value[0],
5989 old_color_clear_value[1],
5990 old_color_clear_value[2],
5991 old_color_clear_value[3]);
5992 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5993 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5994 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5995 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5998 glDisable(GL_SCISSOR_TEST);
5999 checkGLcall("glDisable");
6000 LEAVE_GL();
6002 return WINED3D_OK;
6005 /*****
6006 * Drawing functions
6007 *****/
6008 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6009 UINT PrimitiveCount) {
6011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6012 This->stateBlock->streamIsUP = FALSE;
6014 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6015 debug_d3dprimitivetype(PrimitiveType),
6016 StartVertex, PrimitiveCount);
6017 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6018 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6021 return WINED3D_OK;
6024 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6025 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6026 D3DPRIMITIVETYPE PrimitiveType,
6027 INT baseVIndex, UINT minIndex,
6028 UINT NumVertices, UINT startIndex, UINT primCount) {
6030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6031 UINT idxStride = 2;
6032 IWineD3DIndexBuffer *pIB;
6033 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6035 pIB = This->stateBlock->pIndexData;
6036 This->stateBlock->streamIsUP = FALSE;
6038 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6039 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6040 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6042 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6043 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6044 idxStride = 2;
6045 } else {
6046 idxStride = 4;
6049 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6050 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6052 return WINED3D_OK;
6055 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6056 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6057 UINT VertexStreamZeroStride) {
6058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6060 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6061 debug_d3dprimitivetype(PrimitiveType),
6062 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6064 /* release the stream source */
6065 if (This->stateBlock->streamSource[0] != NULL) {
6066 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6069 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6070 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6071 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6072 This->stateBlock->streamIsUP = TRUE;
6074 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6075 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6077 /* MSDN specifies stream zero settings must be set to NULL */
6078 This->stateBlock->streamStride[0] = 0;
6079 This->stateBlock->streamSource[0] = NULL;
6081 /*stream zero settings set to null at end, as per the msdn */
6082 return WINED3D_OK;
6085 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6086 UINT MinVertexIndex, UINT NumVertices,
6087 UINT PrimitiveCount, CONST void* pIndexData,
6088 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6089 UINT VertexStreamZeroStride) {
6090 int idxStride;
6091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6093 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6094 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6095 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6096 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6098 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6099 idxStride = 2;
6100 } else {
6101 idxStride = 4;
6104 /* release the stream and index data */
6105 if (This->stateBlock->streamSource[0] != NULL) {
6106 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6108 if (This->stateBlock->pIndexData) {
6109 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6112 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6113 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6114 This->stateBlock->streamIsUP = TRUE;
6115 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6117 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6119 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6120 This->stateBlock->streamSource[0] = NULL;
6121 This->stateBlock->streamStride[0] = 0;
6122 This->stateBlock->pIndexData = NULL;
6124 return WINED3D_OK;
6127 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6129 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6130 return WINED3D_OK;
6132 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6133 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6135 HRESULT hr = WINED3D_OK;
6136 WINED3DRESOURCETYPE sourceType;
6137 WINED3DRESOURCETYPE destinationType;
6138 int i ,levels;
6140 /* TODO: think about moving the code into IWineD3DBaseTexture */
6142 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6144 /* verify that the source and destination textures aren't NULL */
6145 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6146 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6147 This, pSourceTexture, pDestinationTexture);
6148 hr = WINED3DERR_INVALIDCALL;
6151 if (pSourceTexture == pDestinationTexture) {
6152 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6153 This, pSourceTexture, pDestinationTexture);
6154 hr = WINED3DERR_INVALIDCALL;
6156 /* Verify that the source and destination textures are the same type */
6157 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6158 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6160 if (sourceType != destinationType) {
6161 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6162 This);
6163 hr = WINED3DERR_INVALIDCALL;
6166 /* check that both textures have the identical numbers of levels */
6167 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6168 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6169 hr = WINED3DERR_INVALIDCALL;
6172 if (WINED3D_OK == hr) {
6174 /* Make sure that the destination texture is loaded */
6175 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6177 /* Update every surface level of the texture */
6178 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6180 switch (sourceType) {
6181 case WINED3DRTYPE_TEXTURE:
6183 IWineD3DSurface *srcSurface;
6184 IWineD3DSurface *destSurface;
6186 for (i = 0 ; i < levels ; ++i) {
6187 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6188 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6189 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6190 IWineD3DSurface_Release(srcSurface);
6191 IWineD3DSurface_Release(destSurface);
6192 if (WINED3D_OK != hr) {
6193 WARN("(%p) : Call to update surface failed\n", This);
6194 return hr;
6198 break;
6199 case WINED3DRTYPE_CUBETEXTURE:
6201 IWineD3DSurface *srcSurface;
6202 IWineD3DSurface *destSurface;
6203 WINED3DCUBEMAP_FACES faceType;
6205 for (i = 0 ; i < levels ; ++i) {
6206 /* Update each cube face */
6207 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6208 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6209 if (WINED3D_OK != hr) {
6210 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6211 } else {
6212 TRACE("Got srcSurface %p\n", srcSurface);
6214 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6215 if (WINED3D_OK != hr) {
6216 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6217 } else {
6218 TRACE("Got desrSurface %p\n", destSurface);
6220 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6221 IWineD3DSurface_Release(srcSurface);
6222 IWineD3DSurface_Release(destSurface);
6223 if (WINED3D_OK != hr) {
6224 WARN("(%p) : Call to update surface failed\n", This);
6225 return hr;
6230 break;
6231 #if 0 /* TODO: Add support for volume textures */
6232 case WINED3DRTYPE_VOLUMETEXTURE:
6234 IWineD3DVolume srcVolume = NULL;
6235 IWineD3DSurface destVolume = NULL;
6237 for (i = 0 ; i < levels ; ++i) {
6238 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6239 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6240 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6241 IWineD3DVolume_Release(srcSurface);
6242 IWineD3DVolume_Release(destSurface);
6243 if (WINED3D_OK != hr) {
6244 WARN("(%p) : Call to update volume failed\n", This);
6245 return hr;
6249 break;
6250 #endif
6251 default:
6252 FIXME("(%p) : Unsupported source and destination type\n", This);
6253 hr = WINED3DERR_INVALIDCALL;
6257 return hr;
6260 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6261 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6262 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6265 TRACE("(%p) : stub\n", This);
6266 return WINED3D_OK;
6268 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6270 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6271 * NOTE It may be best to move the code into surface to occomplish this
6272 ****************************************/
6274 WINED3DSURFACE_DESC surfaceDesc;
6275 unsigned int surfaceWidth, surfaceHeight;
6276 glDescriptor *targetGlDescription = NULL;
6277 glDescriptor *surfaceGlDescription = NULL;
6278 IWineD3DSwapChainImpl *container = NULL;
6280 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6281 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6282 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6284 surfaceDesc.Width = &surfaceWidth;
6285 surfaceDesc.Height = &surfaceHeight;
6286 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6287 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6289 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6290 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6291 ENTER_GL();
6292 /* TODO: opengl Context switching for swapchains etc... */
6293 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6294 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6295 glReadBuffer(GL_BACK);
6296 vcheckGLcall("glReadBuffer(GL_BACK)");
6297 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6298 glReadBuffer(GL_FRONT);
6299 vcheckGLcall("glReadBuffer(GL_FRONT)");
6300 } else if (pRenderTarget == This->depthStencilBuffer) {
6301 FIXME("Reading of depthstencil not yet supported\n");
6304 glReadPixels(surfaceGlDescription->target,
6305 surfaceGlDescription->level,
6306 surfaceWidth,
6307 surfaceHeight,
6308 surfaceGlDescription->glFormat,
6309 surfaceGlDescription->glType,
6310 (void *)IWineD3DSurface_GetData(pSurface));
6311 vcheckGLcall("glReadPixels(...)");
6312 if(NULL != container ){
6313 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6315 } else {
6316 IWineD3DBaseTexture *container;
6317 GLenum textureDimensions = GL_TEXTURE_2D;
6319 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6320 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6321 IWineD3DBaseTexture_Release(container);
6323 /* TODO: 2D -> Cube surface coppies etc.. */
6324 if (surfaceGlDescription->target != textureDimensions) {
6325 FIXME("(%p) : Texture dimension mismatch\n", This);
6327 glEnable(textureDimensions);
6328 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6329 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6330 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6331 vcheckGLcall("glBindTexture");
6332 glGetTexImage(surfaceGlDescription->target,
6333 surfaceGlDescription->level,
6334 surfaceGlDescription->glFormat,
6335 surfaceGlDescription->glType,
6336 (void *)IWineD3DSurface_GetData(pSurface));
6337 glDisable(textureDimensions);
6338 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6341 LEAVE_GL();
6342 return WINED3D_OK;
6345 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6346 IWineD3DSwapChain *swapChain;
6347 HRESULT hr;
6348 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6349 if(hr == WINED3D_OK) {
6350 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6351 IWineD3DSwapChain_Release(swapChain);
6353 return hr;
6356 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6358 /* return a sensible default */
6359 *pNumPasses = 1;
6360 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6361 FIXME("(%p) : stub\n", This);
6362 return WINED3D_OK;
6365 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6367 int j;
6368 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6369 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6370 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6371 return WINED3DERR_INVALIDCALL;
6373 for (j = 0; j < 256; ++j) {
6374 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6375 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6376 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6377 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6379 TRACE("(%p) : returning\n", This);
6380 return WINED3D_OK;
6383 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6385 int j;
6386 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6387 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6388 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6389 return WINED3DERR_INVALIDCALL;
6391 for (j = 0; j < 256; ++j) {
6392 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6393 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6394 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6395 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6397 TRACE("(%p) : returning\n", This);
6398 return WINED3D_OK;
6401 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6403 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6404 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6405 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6406 return WINED3DERR_INVALIDCALL;
6408 /*TODO: stateblocks */
6409 This->currentPalette = PaletteNumber;
6410 TRACE("(%p) : returning\n", This);
6411 return WINED3D_OK;
6414 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6416 if (PaletteNumber == NULL) {
6417 WARN("(%p) : returning Invalid Call\n", This);
6418 return WINED3DERR_INVALIDCALL;
6420 /*TODO: stateblocks */
6421 *PaletteNumber = This->currentPalette;
6422 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6423 return WINED3D_OK;
6426 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6428 static BOOL showFixmes = TRUE;
6429 if (showFixmes) {
6430 FIXME("(%p) : stub\n", This);
6431 showFixmes = FALSE;
6434 This->softwareVertexProcessing = bSoftware;
6435 return WINED3D_OK;
6439 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6441 static BOOL showFixmes = TRUE;
6442 if (showFixmes) {
6443 FIXME("(%p) : stub\n", This);
6444 showFixmes = FALSE;
6446 return This->softwareVertexProcessing;
6450 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6452 IWineD3DSwapChain *swapChain;
6453 HRESULT hr;
6455 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6457 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6458 if(hr == WINED3D_OK){
6459 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6460 IWineD3DSwapChain_Release(swapChain);
6461 }else{
6462 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6464 return hr;
6468 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6470 static BOOL showfixmes = TRUE;
6471 if(nSegments != 0.0f) {
6472 if( showfixmes) {
6473 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6474 showfixmes = FALSE;
6477 return WINED3D_OK;
6480 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6482 static BOOL showfixmes = TRUE;
6483 if( showfixmes) {
6484 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6485 showfixmes = FALSE;
6487 return 0.0f;
6490 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6492 /** TODO: remove casts to IWineD3DSurfaceImpl
6493 * NOTE: move code to surface to accomplish this
6494 ****************************************/
6495 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6496 int srcWidth, srcHeight;
6497 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6498 WINED3DFORMAT destFormat, srcFormat;
6499 UINT destSize;
6500 int destLeft, destTop;
6501 WINED3DPOOL srcPool, destPool;
6502 int offset = 0;
6503 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6504 glDescriptor *glDescription = NULL;
6505 GLenum textureDimensions = GL_TEXTURE_2D;
6506 IWineD3DBaseTexture *baseTexture;
6508 WINED3DSURFACE_DESC winedesc;
6510 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6511 memset(&winedesc, 0, sizeof(winedesc));
6512 winedesc.Width = &srcSurfaceWidth;
6513 winedesc.Height = &srcSurfaceHeight;
6514 winedesc.Pool = &srcPool;
6515 winedesc.Format = &srcFormat;
6517 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6519 winedesc.Width = &destSurfaceWidth;
6520 winedesc.Height = &destSurfaceHeight;
6521 winedesc.Pool = &destPool;
6522 winedesc.Format = &destFormat;
6523 winedesc.Size = &destSize;
6525 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6527 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6528 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6529 return WINED3DERR_INVALIDCALL;
6532 if (destFormat == WINED3DFMT_UNKNOWN) {
6533 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6534 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6536 /* Get the update surface description */
6537 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6540 /* Make sure the surface is loaded and up to date */
6541 IWineD3DSurface_PreLoad(pDestinationSurface);
6543 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6545 ENTER_GL();
6547 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6548 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6549 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6550 destLeft = pDestPoint ? pDestPoint->x : 0;
6551 destTop = pDestPoint ? pDestPoint->y : 0;
6554 /* This function doesn't support compressed textures
6555 the pitch is just bytesPerPixel * width */
6556 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6557 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6558 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6559 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6561 /* TODO DXT formats */
6563 if(pSourceRect != NULL && pSourceRect->top != 0){
6564 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6566 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6567 ,This
6568 ,glDescription->level
6569 ,destLeft
6570 ,destTop
6571 ,srcWidth
6572 ,srcHeight
6573 ,glDescription->glFormat
6574 ,glDescription->glType
6575 ,IWineD3DSurface_GetData(pSourceSurface)
6578 /* Sanity check */
6579 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6581 /* need to lock the surface to get the data */
6582 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6585 /* TODO: Cube and volume support */
6586 if(rowoffset != 0){
6587 /* not a whole row so we have to do it a line at a time */
6588 int j;
6590 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6591 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6593 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6595 glTexSubImage2D(glDescription->target
6596 ,glDescription->level
6597 ,destLeft
6599 ,srcWidth
6601 ,glDescription->glFormat
6602 ,glDescription->glType
6603 ,data /* could be quicker using */
6605 data += rowoffset;
6608 } else { /* Full width, so just write out the whole texture */
6610 if (WINED3DFMT_DXT1 == destFormat ||
6611 WINED3DFMT_DXT2 == destFormat ||
6612 WINED3DFMT_DXT3 == destFormat ||
6613 WINED3DFMT_DXT4 == destFormat ||
6614 WINED3DFMT_DXT5 == destFormat) {
6615 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6616 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6617 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6618 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6619 } if (destFormat != srcFormat) {
6620 FIXME("Updating mixed format compressed texture is not curretly support\n");
6621 } else {
6622 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6623 glDescription->level,
6624 glDescription->glFormatInternal,
6625 srcWidth,
6626 srcHeight,
6628 destSize,
6629 IWineD3DSurface_GetData(pSourceSurface));
6631 } else {
6632 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6636 } else {
6637 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6639 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6640 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6641 data returned by GetData non-power2 width/height with hardware non-power2
6642 pow2Width/height are set to surface width height, repacking isn't needed so it
6643 doesn't matter which function gets called. */
6644 glTexSubImage2D(glDescription->target
6645 ,glDescription->level
6646 ,destLeft
6647 ,destTop
6648 ,srcWidth
6649 ,srcHeight
6650 ,glDescription->glFormat
6651 ,glDescription->glType
6652 ,IWineD3DSurface_GetData(pSourceSurface)
6654 } else {
6656 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6657 glTexSubImage2D(glDescription->target
6658 ,glDescription->level
6659 ,destLeft
6660 ,destTop
6661 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6662 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6663 ,glDescription->glFormat
6664 ,glDescription->glType
6665 ,IWineD3DSurface_GetData(pSourceSurface)
6671 checkGLcall("glTexSubImage2D");
6673 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6674 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6675 * surface bigger than it needs to be hmm.. */
6676 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6677 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6678 IWineD3DBaseTexture_Release(baseTexture);
6681 glDisable(textureDimensions); /* This needs to be managed better.... */
6682 LEAVE_GL();
6684 return WINED3D_OK;
6687 /* Used by DirectX 8 */
6688 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6689 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6690 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6693 HRESULT hr = WINED3D_OK;
6694 WINED3DFORMAT srcFormat, destFormat;
6695 UINT srcWidth, destWidth;
6696 UINT srcHeight, destHeight;
6697 UINT srcSize;
6698 WINED3DSURFACE_DESC winedesc;
6700 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6701 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6704 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6705 memset(&winedesc, 0, sizeof(winedesc));
6707 winedesc.Format = &srcFormat;
6708 winedesc.Width = &srcWidth;
6709 winedesc.Height = &srcHeight;
6710 winedesc.Size = &srcSize;
6711 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6713 winedesc.Format = &destFormat;
6714 winedesc.Width = &destWidth;
6715 winedesc.Height = &destHeight;
6716 winedesc.Size = NULL;
6717 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6719 /* Check that the source and destination formats match */
6720 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6721 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6722 return WINED3DERR_INVALIDCALL;
6723 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6724 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6725 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6726 destFormat = srcFormat;
6729 /* Quick if complete copy ... */
6730 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6732 if (srcWidth == destWidth && srcHeight == destHeight) {
6733 WINED3DLOCKED_RECT lrSrc;
6734 WINED3DLOCKED_RECT lrDst;
6735 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6736 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6737 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6739 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6741 IWineD3DSurface_UnlockRect(pSourceSurface);
6742 IWineD3DSurface_UnlockRect(pDestinationSurface);
6743 TRACE("Unlocked src and dst\n");
6745 } else {
6747 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6748 hr = WINED3DERR_INVALIDCALL;
6751 } else {
6753 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6755 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6756 unsigned int i;
6758 /* Copy rect by rect */
6759 for (i = 0; i < cRects; ++i) {
6760 CONST RECT* r = &pSourceRectsArray[i];
6761 CONST POINT* p = &pDestPointsArray[i];
6762 int copyperline;
6763 int j;
6764 WINED3DLOCKED_RECT lrSrc;
6765 WINED3DLOCKED_RECT lrDst;
6766 RECT dest_rect;
6768 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6769 if (srcFormat == WINED3DFMT_DXT1) {
6770 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6771 } else {
6772 copyperline = ((r->right - r->left) * bytesPerPixel);
6775 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6776 dest_rect.left = p->x;
6777 dest_rect.top = p->y;
6778 dest_rect.right = p->x + (r->right - r->left);
6779 dest_rect.bottom= p->y + (r->bottom - r->top);
6780 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6781 TRACE("Locked src and dst\n");
6783 /* Find where to start */
6784 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6785 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6787 IWineD3DSurface_UnlockRect(pSourceSurface);
6788 IWineD3DSurface_UnlockRect(pDestinationSurface);
6789 TRACE("Unlocked src and dst\n");
6791 } else {
6792 unsigned int i;
6793 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6794 int copyperline;
6795 int j;
6796 WINED3DLOCKED_RECT lrSrc;
6797 WINED3DLOCKED_RECT lrDst;
6798 RECT dest_rect;
6800 for(i=0; i < cRects; i++) {
6801 CONST RECT* r = &pSourceRectsArray[i];
6803 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6804 if (srcFormat == WINED3DFMT_DXT1) {
6805 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6806 } else {
6807 copyperline = ((r->right - r->left) * bytesPerPixel);
6809 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6810 dest_rect.left = 0;
6811 dest_rect.top = 0;
6812 dest_rect.right = r->right - r->left;
6813 dest_rect.bottom= r->bottom - r->top;
6814 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6815 TRACE("Locked src and dst\n");
6816 /* Find where to start */
6817 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6818 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6820 IWineD3DSurface_UnlockRect(pSourceSurface);
6821 IWineD3DSurface_UnlockRect(pDestinationSurface);
6822 TRACE("Unlocked src and dst\n");
6827 return hr;
6830 /* Implementation details at http://developer.nvidia.com/attach/6494
6832 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6833 hmm.. no longer supported use
6834 OpenGL evaluators or tessellate surfaces within your application.
6837 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6838 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6840 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6841 FIXME("(%p) : Stub\n", This);
6842 return WINED3D_OK;
6846 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6849 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6850 FIXME("(%p) : Stub\n", This);
6851 return WINED3D_OK;
6854 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6856 TRACE("(%p) Handle(%d)\n", This, Handle);
6857 FIXME("(%p) : Stub\n", This);
6858 return WINED3D_OK;
6861 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6863 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6864 DDBLTFX BltFx;
6865 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6867 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6868 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6869 return WINED3DERR_INVALIDCALL;
6872 /* Just forward this to the DirectDraw blitting engine */
6873 memset(&BltFx, 0, sizeof(BltFx));
6874 BltFx.dwSize = sizeof(BltFx);
6875 BltFx.u5.dwFillColor = color;
6876 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6879 /* rendertarget and deptth stencil functions */
6880 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6883 /* FIXME: Implelent RenderTargetIndex >0 */
6884 if(RenderTargetIndex > 0)
6885 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6887 *ppRenderTarget = This->renderTarget;
6888 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6889 /* Note inc ref on returned surface */
6890 if(*ppRenderTarget != NULL)
6891 IWineD3DSurface_AddRef(*ppRenderTarget);
6892 return WINED3D_OK;
6895 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6897 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6898 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6899 IWineD3DSwapChainImpl *Swapchain;
6900 HRESULT hr;
6902 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6904 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6905 if(hr != WINED3D_OK) {
6906 ERR("Can't get the swapchain\n");
6907 return hr;
6910 /* Make sure to release the swapchain */
6911 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6913 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6914 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6915 return WINED3DERR_INVALIDCALL;
6917 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6918 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6919 return WINED3DERR_INVALIDCALL;
6922 if(Swapchain->frontBuffer != Front) {
6923 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6925 if(Swapchain->frontBuffer)
6926 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6927 Swapchain->frontBuffer = Front;
6929 if(Swapchain->frontBuffer) {
6930 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6934 if(Back && !Swapchain->backBuffer) {
6935 /* We need memory for the back buffer array - only one back buffer this way */
6936 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6937 if(!Swapchain->backBuffer) {
6938 ERR("Out of memory\n");
6939 return E_OUTOFMEMORY;
6943 if(Swapchain->backBuffer[0] != Back) {
6944 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6945 ENTER_GL();
6946 if(!Swapchain->backBuffer[0]) {
6947 /* GL was told to draw to the front buffer at creation,
6948 * undo that
6950 glDrawBuffer(GL_BACK);
6951 checkGLcall("glDrawBuffer(GL_BACK)");
6952 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6953 Swapchain->presentParms.BackBufferCount = 1;
6954 } else if (!Back) {
6955 /* That makes problems - disable for now */
6956 /* glDrawBuffer(GL_FRONT); */
6957 checkGLcall("glDrawBuffer(GL_FRONT)");
6958 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6959 Swapchain->presentParms.BackBufferCount = 0;
6961 LEAVE_GL();
6963 if(Swapchain->backBuffer[0])
6964 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6965 Swapchain->backBuffer[0] = Back;
6967 if(Swapchain->backBuffer[0]) {
6968 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6969 } else {
6970 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6975 return WINED3D_OK;
6978 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6980 *ppZStencilSurface = This->depthStencilBuffer;
6981 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6983 if(*ppZStencilSurface != NULL) {
6984 /* Note inc ref on returned surface */
6985 IWineD3DSurface_AddRef(*ppZStencilSurface);
6987 return WINED3D_OK;
6990 /* internal static helper functions */
6991 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6992 IWineD3DSurface *RenderSurface);
6994 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6996 HRESULT hr = WINED3D_OK;
6997 WINED3DVIEWPORT viewport;
6999 TRACE("(%p) Swapping rendertarget\n",This);
7000 if (RenderTargetIndex > 0) {
7001 FIXME("(%p) Render targets other than the first are not supported\n",This);
7002 RenderTargetIndex = 0;
7005 /* MSDN says that null disables the render target
7006 but a device must always be associated with a render target
7007 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7009 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7010 for more details
7012 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7013 FIXME("Trying to set render target 0 to NULL\n");
7014 return WINED3DERR_INVALIDCALL;
7016 /* TODO: replace Impl* usage with interface usage */
7017 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7018 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);
7019 return WINED3DERR_INVALIDCALL;
7021 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7022 * builds, but I think wine counts as a 'debug' build for now.
7023 ******************************/
7024 /* If we are trying to set what we already have, don't bother */
7025 if (pRenderTarget == This->renderTarget) {
7026 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7027 } else {
7028 /* Otherwise, set the render target up */
7030 if (FALSE == This->sceneEnded) {
7031 IWineD3DDevice_EndScene(iface);
7033 TRACE("clearing renderer\n");
7034 /* IWineD3DDeviceImpl_CleanRender(iface); */
7035 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7036 depending on the renter target implementation being used.
7037 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7038 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7039 stencil buffer and incure an extra memory overhead */
7040 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7043 if (SUCCEEDED(hr)) {
7044 /* Finally, reset the viewport as the MSDN states. */
7045 /* TODO: Replace impl usage */
7046 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7047 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7048 viewport.X = 0;
7049 viewport.Y = 0;
7050 viewport.MaxZ = 1.0f;
7051 viewport.MinZ = 0.0f;
7052 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7053 } else {
7054 FIXME("Unknown error setting the render target\n");
7056 This->sceneEnded = FALSE;
7057 return hr;
7060 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7062 HRESULT hr = WINED3D_OK;
7063 IWineD3DSurface *tmp;
7065 TRACE("(%p) Swapping z-buffer\n",This);
7067 if (pNewZStencil == This->stencilBufferTarget) {
7068 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7069 } else {
7070 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7071 * depending on the renter target implementation being used.
7072 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7073 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7074 * stencil buffer and incure an extra memory overhead
7075 ******************************************************/
7078 tmp = This->stencilBufferTarget;
7079 This->stencilBufferTarget = pNewZStencil;
7080 /* should we be calling the parent or the wined3d surface? */
7081 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7082 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7083 hr = WINED3D_OK;
7084 /** TODO: glEnable/glDisable on depth/stencil depending on
7085 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7086 **********************************************************/
7089 return hr;
7093 #ifdef GL_VERSION_1_3
7094 /* Internal functions not in DirectX */
7095 /** TODO: move this off to the opengl context manager
7096 *(the swapchain doesn't need to know anything about offscreen rendering!)
7097 ****************************************************/
7099 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7103 TRACE("(%p), %p\n", This, swapchain);
7105 if (swapchain->win != swapchain->drawable) {
7106 /* Set everything back the way it ws */
7107 swapchain->render_ctx = swapchain->glCtx;
7108 swapchain->drawable = swapchain->win;
7110 return WINED3D_OK;
7113 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7114 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7116 int i;
7117 unsigned int width;
7118 unsigned int height;
7119 WINED3DFORMAT format;
7120 WINED3DSURFACE_DESC surfaceDesc;
7121 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7122 surfaceDesc.Width = &width;
7123 surfaceDesc.Height = &height;
7124 surfaceDesc.Format = &format;
7125 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7126 *context = NULL;
7127 /* I need a get width/height function (and should do something with the format) */
7128 for (i = 0; i < CONTEXT_CACHE; ++i) {
7129 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7130 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7131 the pSurface can be set to 0 allowing it to be reused from cache **/
7132 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7133 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7134 *context = &This->contextCache[i];
7135 break;
7137 if (This->contextCache[i].Width == 0) {
7138 This->contextCache[i].pSurface = pSurface;
7139 This->contextCache[i].Width = width;
7140 This->contextCache[i].Height = height;
7141 *context = &This->contextCache[i];
7142 break;
7145 if (i == CONTEXT_CACHE) {
7146 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7147 glContext *dropContext = 0;
7148 for (i = 0; i < CONTEXT_CACHE; i++) {
7149 if (This->contextCache[i].usedcount < minUsage) {
7150 dropContext = &This->contextCache[i];
7151 minUsage = This->contextCache[i].usedcount;
7154 /* clean up the context (this doesn't work for ATI at the moment */
7155 #if 0
7156 glXDestroyContext(swapchain->display, dropContext->context);
7157 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7158 #endif
7159 FIXME("Leak\n");
7160 dropContext->Width = 0;
7161 dropContext->pSurface = pSurface;
7162 *context = dropContext;
7163 } else {
7164 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7165 for (i = 0; i < CONTEXT_CACHE; i++) {
7166 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7170 if (*context != NULL)
7171 return WINED3D_OK;
7172 else
7173 return E_OUTOFMEMORY;
7175 #endif
7177 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7178 * the functionality needs splitting up so that we don't do more than we should do.
7179 * this only seems to impact performance a little.
7180 ******************************/
7181 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7182 IWineD3DSurface *RenderSurface) {
7183 HRESULT ret = WINED3DERR_INVALIDCALL;
7184 BOOL oldRecording;
7185 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7188 * Currently only active for GLX >= 1.3
7189 * for others versions we'll have to use GLXPixmaps
7191 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7192 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7193 * so only check OpenGL version
7194 * ..........................
7195 * I don't believe that it is a problem with NVidia headers,
7196 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7197 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7198 * ATI Note:
7199 * Your application will report GLX version 1.2 on glXQueryVersion.
7200 * However, it is safe to call the GLX 1.3 functions as described below.
7202 #if defined(GL_VERSION_1_3)
7204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7205 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7206 IWineD3DSurface *tmp;
7207 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7208 GLXFBConfig* cfgs = NULL;
7209 int nCfgs = 0;
7210 int attribs[256];
7211 int nAttribs = 0;
7212 IWineD3DSwapChain *currentSwapchain;
7213 IWineD3DSwapChainImpl *swapchain;
7214 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7215 * but switch them off if the StencilSurface is set to NULL
7216 ** *********************************************************/
7217 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7218 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7220 /**TODO:
7221 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7222 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7225 #define PUSH1(att) attribs[nAttribs++] = (att);
7226 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7228 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7230 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7231 IWineD3DSwapChainImpl *impSwapChain;
7232 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7233 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7234 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7237 ENTER_GL();
7239 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7240 PUSH2(GLX_X_RENDERABLE, TRUE);
7241 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7242 TRACE("calling makeglcfg\n");
7243 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7244 PUSH1(None);
7246 TRACE("calling chooseFGConfig\n");
7247 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7248 attribs, &nCfgs);
7250 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7251 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7252 why we failed and only show this message once! */
7253 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"); /**/
7254 nAttribs = 0;
7255 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7256 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7257 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7258 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7259 TRACE("calling makeglcfg\n");
7260 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7261 PUSH1(None);
7262 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7263 attribs, &nCfgs);
7266 if (NULL != cfgs) {
7267 #ifdef EXTRA_TRACES
7268 int i;
7269 for (i = 0; i < nCfgs; ++i) {
7270 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7271 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7272 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7275 if (NULL != This->renderTarget) {
7276 glFlush();
7277 vcheckGLcall("glFlush");
7278 /** This is only useful if the old render target was a swapchain,
7279 * we need to supercede this with a function that displays
7280 * the current buffer on the screen. This is easy to do in glx1.3 but
7281 * we need to do copy-write pixels in glx 1.2.
7282 ************************************************/
7283 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7285 printf("Hit Enter to get next frame ...\n");
7286 getchar();
7288 #endif
7291 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7292 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7293 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7297 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7298 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7299 **********************************************************************/
7300 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7301 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7302 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7303 TRACE("making swapchain active\n");
7304 if (RenderSurface != This->renderTarget) {
7305 BOOL backbuf = FALSE;
7306 int i;
7308 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7309 if(RenderSurface == swapchain->backBuffer[i]) {
7310 backbuf = TRUE;
7311 break;
7315 if (backbuf) {
7316 } else {
7317 /* This could be flagged so that some operations work directly with the front buffer */
7318 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7320 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7321 == False) {
7322 TRACE("Error in setting current context: context %p drawable %ld !\n",
7323 impSwapChain->glCtx, impSwapChain->win);
7326 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7328 checkGLcall("glXMakeContextCurrent");
7330 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7332 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7334 /** ********************************************************************
7335 * This is a quickly hacked out implementation of offscreen textures.
7336 * It will work in most cases but there may be problems if the client
7337 * modifies the texture directly, or expects the contents of the rendertarget
7338 * to be persistent.
7340 * There are some real speed vs compatibility issues here:
7341 * we should really use a new context for every texture, but that eats ram.
7342 * we should also be restoring the texture to the pbuffer but that eats CPU
7343 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7344 * but if this means reusing the display backbuffer then we need to make sure that
7345 * states are correctly preserved.
7346 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7347 * and gain a good performance increase at the cost of compatibility.
7348 * I would suggest that, when this is the case, a user configurable flag be made
7349 * available, allowing the user to choose the best emulated experience for them.
7350 *********************************************************************/
7352 XVisualInfo *visinfo;
7353 glContext *newContext;
7355 /* Here were using a shared context model */
7356 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7357 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7360 /* If the context doesn't exist then create a new one */
7361 /* TODO: This should really be part of findGlContext */
7362 if (NULL == newContext->context) {
7364 TRACE("making new buffer\n");
7365 nAttribs = 0;
7366 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7367 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7368 PUSH1(None);
7370 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7372 /** ****************************************
7373 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7374 *they note:
7375 * In future releases, we may provide the calls glXCreateNewContext,
7376 * glXQueryDrawable and glXMakeContextCurrent.
7377 * so until then we have to use glXGetVisualFromFBConfig &co..
7378 ********************************************/
7381 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7382 if (!visinfo) {
7383 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7384 } else {
7385 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7386 XFree(visinfo);
7389 if (NULL == newContext || NULL == newContext->context) {
7390 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7391 } else {
7392 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7393 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7394 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7397 /* Clean up the old context */
7398 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7399 /* Set the current context of the swapchain to the new context */
7400 impSwapChain->drawable = newContext->drawable;
7401 impSwapChain->render_ctx = newContext->context;
7405 /* Disable recording, and apply the stateblock to the new context
7406 * FIXME: This is a bit of a hack, each context should know it's own state,
7407 * the directX current directX state should then be applied to the context */
7408 oldUpdateStateBlock = This->updateStateBlock;
7409 oldRecording= This->isRecordingState;
7410 This->isRecordingState = FALSE;
7411 This->updateStateBlock = This->stateBlock;
7412 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7414 /* clean up the current rendertargets swapchain (if it belonged to one) */
7415 if (currentSwapchain != NULL) {
7416 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7419 /* Were done with the opengl context management, setup the rendertargets */
7421 tmp = This->renderTarget;
7422 This->renderTarget = RenderSurface;
7423 IWineD3DSurface_AddRef(This->renderTarget);
7424 IWineD3DSurface_Release(tmp);
7427 DWORD value;
7429 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7430 /* Check that the container is not a swapchain member */
7432 IWineD3DSwapChain *tmpSwapChain;
7433 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7434 This->renderUpsideDown = TRUE;
7435 }else{
7436 This->renderUpsideDown = FALSE;
7437 IWineD3DSwapChain_Release(tmpSwapChain);
7439 /* Force updating the cull mode */
7440 TRACE("setting render state\n");
7441 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7442 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7444 /* Force updating projection matrix */
7445 This->last_was_rhw = FALSE;
7446 This->proj_valid = FALSE;
7449 /* Restore recording state */
7450 This->isRecordingState = oldRecording;
7451 This->updateStateBlock = oldUpdateStateBlock;
7453 ret = WINED3D_OK;
7455 if (cfgs != NULL) {
7456 XFree(cfgs);
7457 } else {
7458 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7459 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7462 #undef PUSH1
7463 #undef PUSH2
7464 if ( NULL != impSwapChain) {
7465 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7467 LEAVE_GL();
7469 #endif
7470 return ret;
7473 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7474 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7476 /* TODO: the use of Impl is deprecated. */
7477 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7479 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7481 /* some basic validation checks */
7482 if(This->cursorTexture) {
7483 ENTER_GL();
7484 glDeleteTextures(1, &This->cursorTexture);
7485 LEAVE_GL();
7486 This->cursorTexture = 0;
7489 if(pCursorBitmap) {
7490 /* MSDN: Cursor must be A8R8G8B8 */
7491 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7492 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7493 return WINED3DERR_INVALIDCALL;
7496 /* MSDN: Cursor must be smaller than the display mode */
7497 if(pSur->currentDesc.Width > This->ddraw_width ||
7498 pSur->currentDesc.Height > This->ddraw_height) {
7499 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);
7500 return WINED3DERR_INVALIDCALL;
7503 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7504 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7505 * Texture and Blitting code to draw the cursor
7507 pSur->Flags |= SFLAG_FORCELOAD;
7508 IWineD3DSurface_PreLoad(pCursorBitmap);
7509 pSur->Flags &= ~SFLAG_FORCELOAD;
7510 /* Do not store the surface's pointer because the application may release
7511 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7512 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7514 This->cursorTexture = pSur->glDescription.textureName;
7515 This->cursorWidth = pSur->currentDesc.Width;
7516 This->cursorHeight = pSur->currentDesc.Height;
7517 pSur->glDescription.textureName = 0; /* Prevent the texture from beeing changed or deleted */
7520 This->xHotSpot = XHotSpot;
7521 This->yHotSpot = YHotSpot;
7522 return WINED3D_OK;
7525 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7527 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7529 This->xScreenSpace = XScreenSpace;
7530 This->yScreenSpace = YScreenSpace;
7532 return;
7536 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7538 TRACE("(%p) : visible(%d)\n", This, bShow);
7540 This->bCursorVisible = bShow;
7542 return WINED3D_OK;
7545 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7547 TRACE("(%p) : state (%lu)\n", This, This->state);
7548 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7549 switch (This->state) {
7550 case WINED3D_OK:
7551 return WINED3D_OK;
7552 case WINED3DERR_DEVICELOST:
7554 ResourceList *resourceList = This->resources;
7555 while (NULL != resourceList) {
7556 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7557 return WINED3DERR_DEVICENOTRESET;
7558 resourceList = resourceList->next;
7560 return WINED3DERR_DEVICELOST;
7562 case WINED3DERR_DRIVERINTERNALERROR:
7563 return WINED3DERR_DRIVERINTERNALERROR;
7566 /* Unknown state */
7567 return WINED3DERR_DRIVERINTERNALERROR;
7571 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7573 /** FIXME: Resource tracking needs to be done,
7574 * The closes we can do to this is set the priorities of all managed textures low
7575 * and then reset them.
7576 ***********************************************************/
7577 FIXME("(%p) : stub\n", This);
7578 return WINED3D_OK;
7581 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7583 /** FIXME: Resource trascking needs to be done.
7584 * in effect this pulls all non only default
7585 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7586 * and should clear down the context and set it up according to pPresentationParameters
7587 ***********************************************************/
7588 FIXME("(%p) : stub\n", This);
7589 return WINED3D_OK;
7592 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7594 /** FIXME: always true at the moment **/
7595 if(bEnableDialogs == FALSE) {
7596 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7598 return WINED3D_OK;
7602 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7604 TRACE("(%p) : pParameters %p\n", This, pParameters);
7606 *pParameters = This->createParms;
7607 return WINED3D_OK;
7610 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7611 IWineD3DSwapChain *swapchain;
7612 HRESULT hrc = WINED3D_OK;
7614 TRACE("Relaying to swapchain\n");
7616 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7617 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7618 IWineD3DSwapChain_Release(swapchain);
7620 return;
7623 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7624 IWineD3DSwapChain *swapchain;
7625 HRESULT hrc = WINED3D_OK;
7627 TRACE("Relaying to swapchain\n");
7629 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7630 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7631 IWineD3DSwapChain_Release(swapchain);
7633 return;
7637 /** ********************************************************
7638 * Notification functions
7639 ** ********************************************************/
7640 /** This function must be called in the release of a resource when ref == 0,
7641 * the contents of resource must still be correct,
7642 * any handels to other resource held by the caller must be closed
7643 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7644 *****************************************************/
7645 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7647 ResourceList* resourceList;
7649 TRACE("(%p) : resource %p\n", This, resource);
7650 #if 0
7651 EnterCriticalSection(&resourceStoreCriticalSection);
7652 #endif
7653 /* add a new texture to the frot of the linked list */
7654 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7655 resourceList->resource = resource;
7657 /* Get the old head */
7658 resourceList->next = This->resources;
7660 This->resources = resourceList;
7661 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7663 #if 0
7664 LeaveCriticalSection(&resourceStoreCriticalSection);
7665 #endif
7666 return;
7669 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7671 ResourceList* resourceList = NULL;
7672 ResourceList* previousResourceList = NULL;
7674 TRACE("(%p) : resource %p\n", This, resource);
7676 #if 0
7677 EnterCriticalSection(&resourceStoreCriticalSection);
7678 #endif
7679 resourceList = This->resources;
7681 while (resourceList != NULL) {
7682 if(resourceList->resource == resource) break;
7683 previousResourceList = resourceList;
7684 resourceList = resourceList->next;
7687 if (resourceList == NULL) {
7688 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7689 #if 0
7690 LeaveCriticalSection(&resourceStoreCriticalSection);
7691 #endif
7692 return;
7693 } else {
7694 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7696 /* make sure we don't leave a hole in the list */
7697 if (previousResourceList != NULL) {
7698 previousResourceList->next = resourceList->next;
7699 } else {
7700 This->resources = resourceList->next;
7703 #if 0
7704 LeaveCriticalSection(&resourceStoreCriticalSection);
7705 #endif
7706 return;
7710 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7712 int counter;
7714 TRACE("(%p) : resource %p\n", This, resource);
7715 switch(IWineD3DResource_GetType(resource)){
7716 case WINED3DRTYPE_SURFACE:
7717 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7718 break;
7719 case WINED3DRTYPE_TEXTURE:
7720 case WINED3DRTYPE_CUBETEXTURE:
7721 case WINED3DRTYPE_VOLUMETEXTURE:
7722 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7723 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7724 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7725 This->stateBlock->textures[counter] = NULL;
7727 if (This->updateStateBlock != This->stateBlock ){
7728 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7729 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7730 This->updateStateBlock->textures[counter] = NULL;
7734 break;
7735 case WINED3DRTYPE_VOLUME:
7736 /* TODO: nothing really? */
7737 break;
7738 case WINED3DRTYPE_VERTEXBUFFER:
7739 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7741 int streamNumber;
7742 TRACE("Cleaning up stream pointers\n");
7744 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7745 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7746 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7748 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7749 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7750 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7751 This->updateStateBlock->streamSource[streamNumber] = 0;
7752 /* Set changed flag? */
7755 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) */
7756 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7757 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7758 This->stateBlock->streamSource[streamNumber] = 0;
7761 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7762 else { /* This shouldn't happen */
7763 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7765 #endif
7769 break;
7770 case WINED3DRTYPE_INDEXBUFFER:
7771 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7772 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7773 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7774 This->updateStateBlock->pIndexData = NULL;
7777 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7778 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7779 This->stateBlock->pIndexData = NULL;
7783 break;
7784 default:
7785 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7786 break;
7790 /* Remove the resoruce from the resourceStore */
7791 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7793 TRACE("Resource released\n");
7797 /**********************************************************
7798 * IWineD3DDevice VTbl follows
7799 **********************************************************/
7801 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7803 /*** IUnknown methods ***/
7804 IWineD3DDeviceImpl_QueryInterface,
7805 IWineD3DDeviceImpl_AddRef,
7806 IWineD3DDeviceImpl_Release,
7807 /*** IWineD3DDevice methods ***/
7808 IWineD3DDeviceImpl_GetParent,
7809 /*** Creation methods**/
7810 IWineD3DDeviceImpl_CreateVertexBuffer,
7811 IWineD3DDeviceImpl_CreateIndexBuffer,
7812 IWineD3DDeviceImpl_CreateStateBlock,
7813 IWineD3DDeviceImpl_CreateSurface,
7814 IWineD3DDeviceImpl_CreateTexture,
7815 IWineD3DDeviceImpl_CreateVolumeTexture,
7816 IWineD3DDeviceImpl_CreateVolume,
7817 IWineD3DDeviceImpl_CreateCubeTexture,
7818 IWineD3DDeviceImpl_CreateQuery,
7819 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7820 IWineD3DDeviceImpl_CreateVertexDeclaration,
7821 IWineD3DDeviceImpl_CreateVertexShader,
7822 IWineD3DDeviceImpl_CreatePixelShader,
7823 IWineD3DDeviceImpl_CreatePalette,
7824 /*** Odd functions **/
7825 IWineD3DDeviceImpl_Init3D,
7826 IWineD3DDeviceImpl_Uninit3D,
7827 IWineD3DDeviceImpl_EnumDisplayModes,
7828 IWineD3DDeviceImpl_EvictManagedResources,
7829 IWineD3DDeviceImpl_GetAvailableTextureMem,
7830 IWineD3DDeviceImpl_GetBackBuffer,
7831 IWineD3DDeviceImpl_GetCreationParameters,
7832 IWineD3DDeviceImpl_GetDeviceCaps,
7833 IWineD3DDeviceImpl_GetDirect3D,
7834 IWineD3DDeviceImpl_GetDisplayMode,
7835 IWineD3DDeviceImpl_SetDisplayMode,
7836 IWineD3DDeviceImpl_GetHWND,
7837 IWineD3DDeviceImpl_SetHWND,
7838 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7839 IWineD3DDeviceImpl_GetRasterStatus,
7840 IWineD3DDeviceImpl_GetSwapChain,
7841 IWineD3DDeviceImpl_Reset,
7842 IWineD3DDeviceImpl_SetDialogBoxMode,
7843 IWineD3DDeviceImpl_SetCursorProperties,
7844 IWineD3DDeviceImpl_SetCursorPosition,
7845 IWineD3DDeviceImpl_ShowCursor,
7846 IWineD3DDeviceImpl_TestCooperativeLevel,
7847 /*** Getters and setters **/
7848 IWineD3DDeviceImpl_SetClipPlane,
7849 IWineD3DDeviceImpl_GetClipPlane,
7850 IWineD3DDeviceImpl_SetClipStatus,
7851 IWineD3DDeviceImpl_GetClipStatus,
7852 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7853 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7854 IWineD3DDeviceImpl_SetDepthStencilSurface,
7855 IWineD3DDeviceImpl_GetDepthStencilSurface,
7856 IWineD3DDeviceImpl_SetFVF,
7857 IWineD3DDeviceImpl_GetFVF,
7858 IWineD3DDeviceImpl_SetGammaRamp,
7859 IWineD3DDeviceImpl_GetGammaRamp,
7860 IWineD3DDeviceImpl_SetIndices,
7861 IWineD3DDeviceImpl_GetIndices,
7862 IWineD3DDeviceImpl_SetLight,
7863 IWineD3DDeviceImpl_GetLight,
7864 IWineD3DDeviceImpl_SetLightEnable,
7865 IWineD3DDeviceImpl_GetLightEnable,
7866 IWineD3DDeviceImpl_SetMaterial,
7867 IWineD3DDeviceImpl_GetMaterial,
7868 IWineD3DDeviceImpl_SetNPatchMode,
7869 IWineD3DDeviceImpl_GetNPatchMode,
7870 IWineD3DDeviceImpl_SetPaletteEntries,
7871 IWineD3DDeviceImpl_GetPaletteEntries,
7872 IWineD3DDeviceImpl_SetPixelShader,
7873 IWineD3DDeviceImpl_GetPixelShader,
7874 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7875 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7876 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7877 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7878 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7879 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7880 IWineD3DDeviceImpl_SetRenderState,
7881 IWineD3DDeviceImpl_GetRenderState,
7882 IWineD3DDeviceImpl_SetRenderTarget,
7883 IWineD3DDeviceImpl_GetRenderTarget,
7884 IWineD3DDeviceImpl_SetFrontBackBuffers,
7885 IWineD3DDeviceImpl_SetSamplerState,
7886 IWineD3DDeviceImpl_GetSamplerState,
7887 IWineD3DDeviceImpl_SetScissorRect,
7888 IWineD3DDeviceImpl_GetScissorRect,
7889 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7890 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7891 IWineD3DDeviceImpl_SetStreamSource,
7892 IWineD3DDeviceImpl_GetStreamSource,
7893 IWineD3DDeviceImpl_SetStreamSourceFreq,
7894 IWineD3DDeviceImpl_GetStreamSourceFreq,
7895 IWineD3DDeviceImpl_SetTexture,
7896 IWineD3DDeviceImpl_GetTexture,
7897 IWineD3DDeviceImpl_SetTextureStageState,
7898 IWineD3DDeviceImpl_GetTextureStageState,
7899 IWineD3DDeviceImpl_SetTransform,
7900 IWineD3DDeviceImpl_GetTransform,
7901 IWineD3DDeviceImpl_SetVertexDeclaration,
7902 IWineD3DDeviceImpl_GetVertexDeclaration,
7903 IWineD3DDeviceImpl_SetVertexShader,
7904 IWineD3DDeviceImpl_GetVertexShader,
7905 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7906 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7907 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7908 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7909 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7910 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7911 IWineD3DDeviceImpl_SetViewport,
7912 IWineD3DDeviceImpl_GetViewport,
7913 IWineD3DDeviceImpl_MultiplyTransform,
7914 IWineD3DDeviceImpl_ValidateDevice,
7915 IWineD3DDeviceImpl_ProcessVertices,
7916 /*** State block ***/
7917 IWineD3DDeviceImpl_BeginStateBlock,
7918 IWineD3DDeviceImpl_EndStateBlock,
7919 /*** Scene management ***/
7920 IWineD3DDeviceImpl_BeginScene,
7921 IWineD3DDeviceImpl_EndScene,
7922 IWineD3DDeviceImpl_Present,
7923 IWineD3DDeviceImpl_Clear,
7924 /*** Drawing ***/
7925 IWineD3DDeviceImpl_DrawPrimitive,
7926 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7927 IWineD3DDeviceImpl_DrawPrimitiveUP,
7928 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7929 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7930 IWineD3DDeviceImpl_DrawRectPatch,
7931 IWineD3DDeviceImpl_DrawTriPatch,
7932 IWineD3DDeviceImpl_DeletePatch,
7933 IWineD3DDeviceImpl_ColorFill,
7934 IWineD3DDeviceImpl_UpdateTexture,
7935 IWineD3DDeviceImpl_UpdateSurface,
7936 IWineD3DDeviceImpl_CopyRects,
7937 IWineD3DDeviceImpl_StretchRect,
7938 IWineD3DDeviceImpl_GetRenderTargetData,
7939 IWineD3DDeviceImpl_GetFrontBufferData,
7940 /*** Internal use IWineD3DDevice methods ***/
7941 IWineD3DDeviceImpl_SetupTextureStates,
7942 /*** object tracking ***/
7943 IWineD3DDeviceImpl_ResourceReleased
7947 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7948 WINED3DRS_ALPHABLENDENABLE ,
7949 WINED3DRS_ALPHAFUNC ,
7950 WINED3DRS_ALPHAREF ,
7951 WINED3DRS_ALPHATESTENABLE ,
7952 WINED3DRS_BLENDOP ,
7953 WINED3DRS_COLORWRITEENABLE ,
7954 WINED3DRS_DESTBLEND ,
7955 WINED3DRS_DITHERENABLE ,
7956 WINED3DRS_FILLMODE ,
7957 WINED3DRS_FOGDENSITY ,
7958 WINED3DRS_FOGEND ,
7959 WINED3DRS_FOGSTART ,
7960 WINED3DRS_LASTPIXEL ,
7961 WINED3DRS_SHADEMODE ,
7962 WINED3DRS_SRCBLEND ,
7963 WINED3DRS_STENCILENABLE ,
7964 WINED3DRS_STENCILFAIL ,
7965 WINED3DRS_STENCILFUNC ,
7966 WINED3DRS_STENCILMASK ,
7967 WINED3DRS_STENCILPASS ,
7968 WINED3DRS_STENCILREF ,
7969 WINED3DRS_STENCILWRITEMASK ,
7970 WINED3DRS_STENCILZFAIL ,
7971 WINED3DRS_TEXTUREFACTOR ,
7972 WINED3DRS_WRAP0 ,
7973 WINED3DRS_WRAP1 ,
7974 WINED3DRS_WRAP2 ,
7975 WINED3DRS_WRAP3 ,
7976 WINED3DRS_WRAP4 ,
7977 WINED3DRS_WRAP5 ,
7978 WINED3DRS_WRAP6 ,
7979 WINED3DRS_WRAP7 ,
7980 WINED3DRS_ZENABLE ,
7981 WINED3DRS_ZFUNC ,
7982 WINED3DRS_ZWRITEENABLE
7985 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7986 WINED3DTSS_ADDRESSW ,
7987 WINED3DTSS_ALPHAARG0 ,
7988 WINED3DTSS_ALPHAARG1 ,
7989 WINED3DTSS_ALPHAARG2 ,
7990 WINED3DTSS_ALPHAOP ,
7991 WINED3DTSS_BUMPENVLOFFSET ,
7992 WINED3DTSS_BUMPENVLSCALE ,
7993 WINED3DTSS_BUMPENVMAT00 ,
7994 WINED3DTSS_BUMPENVMAT01 ,
7995 WINED3DTSS_BUMPENVMAT10 ,
7996 WINED3DTSS_BUMPENVMAT11 ,
7997 WINED3DTSS_COLORARG0 ,
7998 WINED3DTSS_COLORARG1 ,
7999 WINED3DTSS_COLORARG2 ,
8000 WINED3DTSS_COLOROP ,
8001 WINED3DTSS_RESULTARG ,
8002 WINED3DTSS_TEXCOORDINDEX ,
8003 WINED3DTSS_TEXTURETRANSFORMFLAGS
8006 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8007 WINED3DSAMP_ADDRESSU ,
8008 WINED3DSAMP_ADDRESSV ,
8009 WINED3DSAMP_ADDRESSW ,
8010 WINED3DSAMP_BORDERCOLOR ,
8011 WINED3DSAMP_MAGFILTER ,
8012 WINED3DSAMP_MINFILTER ,
8013 WINED3DSAMP_MIPFILTER ,
8014 WINED3DSAMP_MIPMAPLODBIAS ,
8015 WINED3DSAMP_MAXMIPLEVEL ,
8016 WINED3DSAMP_MAXANISOTROPY ,
8017 WINED3DSAMP_SRGBTEXTURE ,
8018 WINED3DSAMP_ELEMENTINDEX
8021 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8022 WINED3DRS_AMBIENT ,
8023 WINED3DRS_AMBIENTMATERIALSOURCE ,
8024 WINED3DRS_CLIPPING ,
8025 WINED3DRS_CLIPPLANEENABLE ,
8026 WINED3DRS_COLORVERTEX ,
8027 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8028 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8029 WINED3DRS_FOGDENSITY ,
8030 WINED3DRS_FOGEND ,
8031 WINED3DRS_FOGSTART ,
8032 WINED3DRS_FOGTABLEMODE ,
8033 WINED3DRS_FOGVERTEXMODE ,
8034 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8035 WINED3DRS_LIGHTING ,
8036 WINED3DRS_LOCALVIEWER ,
8037 WINED3DRS_MULTISAMPLEANTIALIAS ,
8038 WINED3DRS_MULTISAMPLEMASK ,
8039 WINED3DRS_NORMALIZENORMALS ,
8040 WINED3DRS_PATCHEDGESTYLE ,
8041 WINED3DRS_POINTSCALE_A ,
8042 WINED3DRS_POINTSCALE_B ,
8043 WINED3DRS_POINTSCALE_C ,
8044 WINED3DRS_POINTSCALEENABLE ,
8045 WINED3DRS_POINTSIZE ,
8046 WINED3DRS_POINTSIZE_MAX ,
8047 WINED3DRS_POINTSIZE_MIN ,
8048 WINED3DRS_POINTSPRITEENABLE ,
8049 WINED3DRS_RANGEFOGENABLE ,
8050 WINED3DRS_SPECULARMATERIALSOURCE ,
8051 WINED3DRS_TWEENFACTOR ,
8052 WINED3DRS_VERTEXBLEND
8055 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8056 WINED3DTSS_TEXCOORDINDEX ,
8057 WINED3DTSS_TEXTURETRANSFORMFLAGS
8060 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8061 WINED3DSAMP_DMAPOFFSET