wined3d: Simplify setting the stencil renderstate.
[wine/multimedia.git] / dlls / wined3d / device.c
blob5a07adf85a423986018381fec211f02aa8011b15
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 D3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
75 /* enable pbuffer support for offscreen textures */
76 BOOL pbuffer_support = FALSE;
77 /* allocate one pbuffer per surface */
78 BOOL pbuffer_per_surface = FALSE;
80 /* static function declarations */
81 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
83 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
85 /* helper macros */
86 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
88 #define D3DCREATEOBJECTINSTANCE(object, type) { \
89 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
90 D3DMEMCHECK(object, pp##type); \
91 object->lpVtbl = &IWineD3D##type##_Vtbl; \
92 object->wineD3DDevice = This; \
93 object->parent = parent; \
94 object->ref = 1; \
95 *pp##type = (IWineD3D##type *) object; \
98 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
99 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
100 D3DMEMCHECK(object, pp##type); \
101 object->lpVtbl = &IWineD3D##type##_Vtbl; \
102 object->resource.wineD3DDevice = This; \
103 object->resource.parent = parent; \
104 object->resource.resourceType = d3dtype; \
105 object->resource.ref = 1; \
106 object->resource.pool = Pool; \
107 object->resource.format = Format; \
108 object->resource.usage = Usage; \
109 object->resource.size = _size; \
110 /* Check that we have enough video ram left */ \
111 if (Pool == WINED3DPOOL_DEFAULT) { \
112 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
113 WARN("Out of 'bogus' video memory\n"); \
114 HeapFree(GetProcessHeap(), 0, object); \
115 *pp##type = NULL; \
116 return WINED3DERR_OUTOFVIDEOMEMORY; \
118 globalChangeGlRam(_size); \
120 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
121 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
122 FIXME("Out of memory!\n"); \
123 HeapFree(GetProcessHeap(), 0, object); \
124 *pp##type = NULL; \
125 return WINED3DERR_OUTOFVIDEOMEMORY; \
127 *pp##type = (IWineD3D##type *) object; \
128 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
129 TRACE("(%p) : Created resource %p\n", This, object); \
132 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
133 _basetexture.levels = Levels; \
134 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
135 _basetexture.LOD = 0; \
136 _basetexture.dirty = TRUE; \
139 /**********************************************************
140 * Global variable / Constants follow
141 **********************************************************/
142 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
144 /**********************************************************
145 * Utility functions follow
146 **********************************************************/
147 /* Convert the D3DLIGHT properties into equivalent gl lights */
148 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
150 float quad_att;
151 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
155 glMatrixMode(GL_MODELVIEW);
156 glPushMatrix();
157 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
159 /* Diffuse: */
160 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
161 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
162 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
163 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
164 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
165 checkGLcall("glLightfv");
167 /* Specular */
168 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
169 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
170 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
171 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
172 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
173 checkGLcall("glLightfv");
175 /* Ambient */
176 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
177 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
178 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
179 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
180 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
181 checkGLcall("glLightfv");
183 /* Attenuation - Are these right? guessing... */
184 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
185 checkGLcall("glLightf");
186 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
187 checkGLcall("glLightf");
189 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
190 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
191 } else {
192 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
195 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
196 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
197 checkGLcall("glLightf");
199 switch (lightInfo->OriginalParms.Type) {
200 case D3DLIGHT_POINT:
201 /* Position */
202 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
203 checkGLcall("glLightfv");
204 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
205 checkGLcall("glLightf");
206 /* FIXME: Range */
207 break;
209 case D3DLIGHT_SPOT:
210 /* Position */
211 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
212 checkGLcall("glLightfv");
213 /* Direction */
214 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
215 checkGLcall("glLightfv");
216 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
217 checkGLcall("glLightf");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
219 checkGLcall("glLightf");
220 /* FIXME: Range */
221 break;
223 case D3DLIGHT_DIRECTIONAL:
224 /* Direction */
225 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
226 checkGLcall("glLightfv");
227 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
228 checkGLcall("glLightf");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
230 checkGLcall("glLightf");
231 break;
233 default:
234 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
237 /* Restore the modelview matrix */
238 glPopMatrix();
241 /**********************************************************
242 * GLSL helper functions follow
243 **********************************************************/
245 /** Attach a GLSL pixel or vertex shader object to the shader program */
246 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
249 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
250 if (This->stateBlock->glsl_program && shaderObj != 0) {
251 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
252 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
253 checkGLcall("glAttachObjectARB");
257 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
258 * It sets the programId on the current StateBlock (because it should be called
259 * inside of the DrawPrimitive() part of the render loop).
261 * If a program for the given combination does not exist, create one, and store
262 * the program in the list. If it creates a program, it will link the given
263 * objects, too.
265 * We keep the shader programs around on a list because linking
266 * shader objects together is an expensive operation. It's much
267 * faster to loop through a list of pre-compiled & linked programs
268 * each time that the application sets a new pixel or vertex shader
269 * than it is to re-link them together at that time.
271 * The list will be deleted in IWineD3DDevice::Release().
273 void set_glsl_shader_program(IWineD3DDevice *iface) {
275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
276 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
277 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
278 struct glsl_shader_prog_link *curLink = NULL;
279 struct glsl_shader_prog_link *newLink = NULL;
280 struct list *ptr = NULL;
281 GLhandleARB programId = 0;
282 int i;
283 char glsl_name[8];
285 ptr = list_head( &This->glsl_shader_progs );
286 while (ptr) {
287 /* At least one program exists - see if it matches our ps/vs combination */
288 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
289 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
290 /* Existing Program found, use it */
291 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
292 curLink->programId);
293 This->stateBlock->glsl_program = curLink;
294 return;
296 /* This isn't the entry we need - try the next one */
297 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* If we get to this point, then no matching program exists, so we create one */
301 programId = GL_EXTCALL(glCreateProgramObjectARB());
302 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
304 /* Allocate a new link for the list of programs */
305 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
306 newLink->programId = programId;
307 This->stateBlock->glsl_program = newLink;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
311 int i;
312 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
313 char tmp_name[10];
315 TRACE("Attaching vertex shader to GLSL program\n");
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
322 * GLSL shaders.
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
332 newLink->vertexShader = vshader;
335 /* Attach GLSL pshader */
336 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
337 TRACE("Attaching pixel shader to GLSL program\n");
338 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
339 newLink->pixelShader = pshader;
342 /* Link the program */
343 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
344 GL_EXTCALL(glLinkProgramARB(programId));
345 print_glsl_info_log(&GLINFO_LOCATION, programId);
346 list_add_head( &This->glsl_shader_progs, &newLink->entry);
348 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
349 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
350 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
351 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
353 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
354 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
355 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
356 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
359 return;
362 /** Detach the GLSL pixel or vertex shader object from the shader program */
363 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
367 if (shaderObj != 0 && programId != 0) {
368 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
369 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
370 checkGLcall("glDetachObjectARB");
374 /** Delete a GLSL shader program */
375 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
379 if (obj != 0) {
380 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
381 GL_EXTCALL(glDeleteObjectARB(obj));
382 checkGLcall("glDeleteObjectARB");
386 /** Delete the list of linked programs this shader is associated with.
387 * Also at this point, check to see if there are any objects left attached
388 * to each GLSL program. If not, delete the GLSL program object.
389 * This will be run when a device is released. */
390 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
392 struct list *ptr = NULL;
393 struct glsl_shader_prog_link *curLink = NULL;
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 int numAttached = 0;
397 int i;
398 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
399 (one pixel shader and one vertex shader at most) */
401 ptr = list_head( &This->glsl_shader_progs );
402 while (ptr) {
403 /* First, get the current item,
404 * save the link to the next pointer,
405 * detach and delete shader objects,
406 * then de-allocate the list item's memory */
407 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
408 ptr = list_next( &This->glsl_shader_progs, ptr );
410 /* See if this object is still attached to the program - it may have been detached already */
411 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
412 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
413 for (i = 0; i < numAttached; i++) {
414 detach_glsl_shader(iface, objList[i], curLink->programId);
417 delete_glsl_shader_program(iface, curLink->programId);
419 /* Free the uniform locations */
420 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
421 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
423 /* Free the memory for this list item */
424 HeapFree(GetProcessHeap(), 0, curLink);
429 /* Apply the current values to the specified texture stage */
430 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
432 float col[4];
434 union {
435 float f;
436 DWORD d;
437 } tmpvalue;
439 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
440 clamping, MIPLOD, etc. This will work for up to 16 samplers.
443 if (Sampler >= GL_LIMITS(sampler_stages)) {
444 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
445 return;
447 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
448 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
449 ENTER_GL();
450 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
451 checkGLcall("glActiveTextureARB");
452 LEAVE_GL();
453 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
454 } else if (Sampler > 0) {
455 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
456 return;
459 /* TODO: change this to a lookup table
460 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
461 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
462 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
463 especially when there are a number of groups of states. */
465 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
467 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
468 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
469 /* these are the only two supported states that need to be applied */
470 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
471 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
472 #if 0 /* not supported at the moment */
473 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
474 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
475 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
476 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
477 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
478 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
479 APPLY_STATE(WINED3DTSS_RESULTARG);
480 APPLY_STATE(WINED3DTSS_CONSTANT);
481 #endif
482 /* a quick sanity check in case someone forgot to update this function */
483 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
484 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
486 #undef APPLY_STATE
488 /* apply any sampler states that always need applying */
489 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
490 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
491 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
492 GL_TEXTURE_LOD_BIAS_EXT,
493 tmpvalue.f);
494 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
497 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
498 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
499 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
501 /* TODO: NV_POINT_SPRITE */
502 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
503 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
504 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
505 glDisable(GL_POINT_SMOOTH);
507 /* Centre the texture on the vertex */
508 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
509 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
511 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
512 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
513 checkGLcall("glTexEnvf(...)");
514 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
515 glEnable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
517 } else {
518 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
519 glDisable( GL_POINT_SPRITE_ARB );
520 checkGLcall("glEnable(...)");
524 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
527 /**********************************************************
528 * IUnknown parts follows
529 **********************************************************/
531 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
535 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
536 if (IsEqualGUID(riid, &IID_IUnknown)
537 || IsEqualGUID(riid, &IID_IWineD3DBase)
538 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
539 IUnknown_AddRef(iface);
540 *ppobj = This;
541 return S_OK;
543 *ppobj = NULL;
544 return E_NOINTERFACE;
547 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
549 ULONG refCount = InterlockedIncrement(&This->ref);
551 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
552 return refCount;
555 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 ULONG refCount = InterlockedDecrement(&This->ref);
559 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
561 if (!refCount) {
562 /* TODO: Clean up all the surfaces and textures! */
563 /* NOTE: You must release the parent if the object was created via a callback
564 ** ***************************/
566 /* Delete any GLSL shader programs that may exist */
567 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
568 wined3d_settings.ps_selected_mode == SHADER_GLSL)
569 delete_glsl_shader_list(iface);
571 /* Release the update stateblock */
572 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
573 if(This->updateStateBlock != This->stateBlock)
574 FIXME("(%p) Something's still holding the Update stateblock\n",This);
576 This->updateStateBlock = NULL;
577 { /* because were not doing proper internal refcounts releasing the primary state block
578 causes recursion with the extra checks in ResourceReleased, to avoid this we have
579 to set this->stateBlock = NULL; first */
580 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
581 This->stateBlock = NULL;
583 /* Release the stateblock */
584 if(IWineD3DStateBlock_Release(stateBlock) > 0){
585 FIXME("(%p) Something's still holding the Update stateblock\n",This);
589 if (This->resources != NULL ) {
590 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
591 dumpResources(This->resources);
595 IWineD3D_Release(This->wineD3D);
596 This->wineD3D = NULL;
597 HeapFree(GetProcessHeap(), 0, This);
598 TRACE("Freed device %p\n", This);
599 This = NULL;
601 return refCount;
604 /**********************************************************
605 * IWineD3DDevice implementation follows
606 **********************************************************/
607 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
609 *pParent = This->parent;
610 IUnknown_AddRef(This->parent);
611 return WINED3D_OK;
614 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
615 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
616 GLenum error, glUsage;
617 DWORD vboUsage = object->resource.usage;
618 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
619 WARN("Creating a vbo failed once, not trying again\n");
620 return;
623 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
625 ENTER_GL();
626 /* Make sure that the gl error is cleared. Do not use checkGLcall
627 * here because checkGLcall just prints a fixme and continues. However,
628 * if an error during VBO creation occurs we can fall back to non-vbo operation
629 * with full functionality(but performance loss)
631 while(glGetError() != GL_NO_ERROR);
633 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
634 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
635 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
636 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
637 * to check if the rhw and color values are in the correct format.
640 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
641 error = glGetError();
642 if(object->vbo == 0 || error != GL_NO_ERROR) {
643 WARN("Failed to create a VBO with error %d\n", error);
644 goto error;
647 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
648 error = glGetError();
649 if(error != GL_NO_ERROR) {
650 WARN("Failed to bind the VBO, error %d\n", error);
651 goto error;
654 /* Transformed vertices are horribly inflexible. If the app specifies an
655 * vertex buffer with transformed vertices in default pool without DYNAMIC
656 * usage assume DYNAMIC usage and print a warning. The app will have to update
657 * the vertices regularily for them to be useful
659 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
660 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
661 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
662 vboUsage |= WINED3DUSAGE_DYNAMIC;
665 /* Don't use static, because dx apps tend to update the buffer
666 * quite often even if they specify 0 usage
668 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
669 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
670 TRACE("Gl usage = GL_STREAM_DRAW\n");
671 glUsage = GL_STREAM_DRAW_ARB;
672 break;
673 case D3DUSAGE_WRITEONLY:
674 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
675 glUsage = GL_DYNAMIC_DRAW_ARB;
676 break;
677 case D3DUSAGE_DYNAMIC:
678 TRACE("Gl usage = GL_STREAM_COPY\n");
679 glUsage = GL_STREAM_COPY_ARB;
680 break;
681 default:
682 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
683 glUsage = GL_DYNAMIC_COPY_ARB;
684 break;
687 /* Reserve memory for the buffer. The amount of data won't change
688 * so we are safe with calling glBufferData once with a NULL ptr and
689 * calling glBufferSubData on updates
691 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
692 error = glGetError();
693 if(error != GL_NO_ERROR) {
694 WARN("glBufferDataARB failed with error %d\n", error);
695 goto error;
698 LEAVE_GL();
700 return;
701 error:
702 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
703 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
704 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
705 object->vbo = 0;
706 object->Flags |= VBFLAG_VBOCREATEFAIL;
707 LEAVE_GL();
708 return;
711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
712 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
713 IUnknown *parent) {
714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
715 IWineD3DVertexBufferImpl *object;
716 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
717 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
718 BOOL conv;
719 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
721 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
722 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
724 if(Size == 0) return WINED3DERR_INVALIDCALL;
726 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
727 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
729 object->fvf = FVF;
731 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
732 * drawStridedFast (half-life 2).
734 * Basically converting the vertices in the buffer is quite expensive, and observations
735 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
736 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
738 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
739 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
740 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
741 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
742 * dx7 apps.
743 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
744 * more. In this call we can convert dx7 buffers too.
746 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
747 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
748 (dxVersion > 7 || !conv) ) {
749 CreateVBO(object);
751 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
752 if(dxVersion == 7 && object->vbo) {
753 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
754 object->resource.allocatedMemory = NULL;
758 return WINED3D_OK;
761 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
762 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
763 HANDLE *sharedHandle, IUnknown *parent) {
764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
765 IWineD3DIndexBufferImpl *object;
766 TRACE("(%p) Creating index buffer\n", This);
768 /* Allocate the storage for the device */
769 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
771 /*TODO: use VBO's */
772 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
773 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
776 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
777 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
778 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
780 return WINED3D_OK;
783 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
786 IWineD3DStateBlockImpl *object;
787 int i, j;
788 HRESULT temp_result;
790 D3DCREATEOBJECTINSTANCE(object, StateBlock)
791 object->blockType = Type;
793 /* Special case - Used during initialization to produce a placeholder stateblock
794 so other functions called can update a state block */
795 if (Type == WINED3DSBT_INIT) {
796 /* Don't bother increasing the reference count otherwise a device will never
797 be freed due to circular dependencies */
798 return WINED3D_OK;
801 temp_result = allocate_shader_constants(object);
802 if (WINED3D_OK != temp_result)
803 return temp_result;
805 /* Otherwise, might as well set the whole state block to the appropriate values */
806 if (This->stateBlock != NULL)
807 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
808 else
809 memset(object->streamFreq, 1, sizeof(object->streamFreq));
811 /* Reset the ref and type after kludging it */
812 object->wineD3DDevice = This;
813 object->ref = 1;
814 object->blockType = Type;
816 TRACE("Updating changed flags appropriate for type %d\n", Type);
818 if (Type == WINED3DSBT_ALL) {
820 TRACE("ALL => Pretend everything has changed\n");
821 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
823 } else if (Type == WINED3DSBT_PIXELSTATE) {
825 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
826 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
828 object->changed.pixelShader = TRUE;
830 /* Pixel Shader Constants */
831 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
832 object->changed.pixelShaderConstantsF[i] = TRUE;
833 for (i = 0; i < MAX_CONST_B; ++i)
834 object->changed.pixelShaderConstantsB[i] = TRUE;
835 for (i = 0; i < MAX_CONST_I; ++i)
836 object->changed.pixelShaderConstantsI[i] = TRUE;
838 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
839 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
841 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
842 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
843 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
846 for (j = 0 ; j < 16; j++) {
847 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
849 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
853 } else if (Type == WINED3DSBT_VERTEXSTATE) {
855 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
856 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
858 object->changed.vertexShader = TRUE;
860 /* Vertex Shader Constants */
861 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
862 object->changed.vertexShaderConstantsF[i] = TRUE;
863 for (i = 0; i < MAX_CONST_B; ++i)
864 object->changed.vertexShaderConstantsB[i] = TRUE;
865 for (i = 0; i < MAX_CONST_I; ++i)
866 object->changed.vertexShaderConstantsI[i] = TRUE;
868 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
869 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
871 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
872 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
873 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
876 for (j = 0 ; j < 16; j++){
877 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
878 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
882 /* Duplicate light chain */
884 PLIGHTINFOEL *src = NULL;
885 PLIGHTINFOEL *dst = NULL;
886 PLIGHTINFOEL *newEl = NULL;
887 src = This->stateBlock->lights;
888 object->lights = NULL;
891 while (src) {
892 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
893 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
894 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
895 newEl->prev = dst;
896 newEl->changed = TRUE;
897 newEl->enabledChanged = TRUE;
898 if (dst == NULL) {
899 object->lights = newEl;
900 } else {
901 dst->next = newEl;
903 dst = newEl;
904 src = src->next;
909 } else {
910 FIXME("Unrecognized state block type %d\n", Type);
913 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
914 return WINED3D_OK;
918 /* ************************************
919 MSDN:
920 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
922 Discard
923 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
925 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
927 ******************************** */
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
931 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
932 unsigned int pow2Width, pow2Height;
933 unsigned int Size = 1;
934 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
935 TRACE("(%p) Create surface\n",This);
937 /** FIXME: Check ranges on the inputs are valid
938 * MSDN
939 * MultisampleQuality
940 * [in] Quality level. The valid range is between zero and one less than the level
941 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
942 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
943 * values of paired render targets, depth stencil surfaces, and the MultiSample type
944 * must all match.
945 *******************************/
949 * TODO: Discard MSDN
950 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
952 * If this flag is set, the contents of the depth stencil buffer will be
953 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
954 * with a different depth surface.
956 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
957 ***************************/
959 if(MultisampleQuality < 0) {
960 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
961 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
964 if(MultisampleQuality > 0) {
965 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
966 MultisampleQuality=0;
969 /** FIXME: Check that the format is supported
970 * by the device.
971 *******************************/
973 /* Non-power2 support */
975 /* Find the nearest pow2 match */
976 pow2Width = pow2Height = 1;
977 while (pow2Width < Width) pow2Width <<= 1;
978 while (pow2Height < Height) pow2Height <<= 1;
980 if (pow2Width > Width || pow2Height > Height) {
981 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
982 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
983 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
984 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
985 This, Width, Height);
986 return WINED3DERR_NOTAVAILABLE;
990 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
991 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
992 * space!
993 *********************************/
994 if (WINED3DFMT_UNKNOWN == Format) {
995 Size = 0;
996 } else if (Format == WINED3DFMT_DXT1) {
997 /* DXT1 is half byte per pixel */
998 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1000 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1001 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1002 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1003 } else {
1004 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1007 /** Create and initialise the surface resource **/
1008 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1009 /* "Standalone" surface */
1010 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.MultiSampleType = MultiSample;
1015 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1017 /* Setup some glformat defaults */
1018 object->glDescription.glFormat = tableEntry->glFormat;
1019 object->glDescription.glFormatInternal = tableEntry->glInternal;
1020 object->glDescription.glType = tableEntry->glType;
1022 object->glDescription.textureName = 0;
1023 object->glDescription.level = Level;
1024 object->glDescription.target = GL_TEXTURE_2D;
1026 /* Internal data */
1027 object->pow2Width = pow2Width;
1028 object->pow2Height = pow2Height;
1030 /* Flags */
1031 object->Flags = 0; /* We start without flags set */
1032 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1033 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1034 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1035 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1038 if (WINED3DFMT_UNKNOWN != Format) {
1039 object->bytesPerPixel = tableEntry->bpp;
1040 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1041 } else {
1042 object->bytesPerPixel = 0;
1043 object->pow2Size = 0;
1046 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1048 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1050 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1051 * this function is too deap to need to care about things like this.
1052 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1053 * ****************************************/
1054 switch(Pool) {
1055 case WINED3DPOOL_SCRATCH:
1056 if(Lockable == FALSE)
1057 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1058 which are mutually exclusive, setting lockable to true\n");
1059 Lockable = TRUE;
1060 break;
1061 case WINED3DPOOL_SYSTEMMEM:
1062 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1063 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1064 case WINED3DPOOL_MANAGED:
1065 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1066 Usage of DYNAMIC which are mutually exclusive, not doing \
1067 anything just telling you.\n");
1068 break;
1069 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1070 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1071 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1072 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1073 break;
1074 default:
1075 FIXME("(%p) Unknown pool %d\n", This, Pool);
1076 break;
1079 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1080 FIXME("Trying to create a render target that isn't in the default pool\n");
1083 /* mark the texture as dirty so that it get's loaded first time around*/
1084 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1085 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1086 This, Width, Height, Format, debug_d3dformat(Format),
1087 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1089 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1090 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1091 This->ddraw_primary = (IWineD3DSurface *) object;
1093 /* Look at the implementation and set the correct Vtable */
1094 switch(Impl) {
1095 case SURFACE_OPENGL:
1096 /* Nothing to do, it's set already */
1097 break;
1099 case SURFACE_GDI:
1100 object->lpVtbl = &IWineGDISurface_Vtbl;
1101 break;
1103 default:
1104 /* To be sure to catch this */
1105 ERR("Unknown requested surface implementation %d!\n", Impl);
1106 IWineD3DSurface_Release((IWineD3DSurface *) object);
1107 return WINED3DERR_INVALIDCALL;
1110 /* Call the private setup routine */
1111 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1115 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1116 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1117 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1118 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1121 IWineD3DTextureImpl *object;
1122 unsigned int i;
1123 UINT tmpW;
1124 UINT tmpH;
1125 HRESULT hr;
1126 unsigned int pow2Width = Width;
1127 unsigned int pow2Height = Height;
1130 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#lx\n", This, Width, Height, Levels, Usage);
1131 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1132 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1134 /* TODO: It should only be possible to create textures for formats
1135 that are reported as supported */
1136 if (WINED3DFMT_UNKNOWN >= Format) {
1137 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1138 return WINED3DERR_INVALIDCALL;
1141 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1142 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1143 object->width = Width;
1144 object->height = Height;
1146 /** Non-power2 support **/
1147 /* Find the nearest pow2 match */
1148 pow2Width = pow2Height = 1;
1149 while (pow2Width < Width) pow2Width <<= 1;
1150 while (pow2Height < Height) pow2Height <<= 1;
1152 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1153 /* Precalculated scaling for 'faked' non power of two texture coords */
1154 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1155 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1156 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1158 /* Calculate levels for mip mapping */
1159 if (Levels == 0) {
1160 TRACE("calculating levels %d\n", object->baseTexture.levels);
1161 object->baseTexture.levels++;
1162 tmpW = Width;
1163 tmpH = Height;
1164 while (tmpW > 1 || tmpH > 1) {
1165 tmpW = max(1, tmpW >> 1);
1166 tmpH = max(1, tmpH >> 1);
1167 object->baseTexture.levels++;
1169 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1172 /* Generate all the surfaces */
1173 tmpW = Width;
1174 tmpH = Height;
1175 for (i = 0; i < object->baseTexture.levels; i++)
1177 /* use the callback to create the texture surface */
1178 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1179 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1180 FIXME("Failed to create surface %p\n", object);
1181 /* clean up */
1182 object->surfaces[i] = NULL;
1183 IWineD3DTexture_Release((IWineD3DTexture *)object);
1185 *ppTexture = NULL;
1186 return hr;
1189 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1190 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1191 /* calculate the next mipmap level */
1192 tmpW = max(1, tmpW >> 1);
1193 tmpH = max(1, tmpH >> 1);
1196 TRACE("(%p) : Created texture %p\n", This, object);
1197 return WINED3D_OK;
1200 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1201 UINT Width, UINT Height, UINT Depth,
1202 UINT Levels, DWORD Usage,
1203 WINED3DFORMAT Format, WINED3DPOOL Pool,
1204 IWineD3DVolumeTexture **ppVolumeTexture,
1205 HANDLE *pSharedHandle, IUnknown *parent,
1206 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1209 IWineD3DVolumeTextureImpl *object;
1210 unsigned int i;
1211 UINT tmpW;
1212 UINT tmpH;
1213 UINT tmpD;
1215 /* TODO: It should only be possible to create textures for formats
1216 that are reported as supported */
1217 if (WINED3DFMT_UNKNOWN >= Format) {
1218 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1219 return WINED3DERR_INVALIDCALL;
1222 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1223 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1225 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1226 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1228 object->width = Width;
1229 object->height = Height;
1230 object->depth = Depth;
1232 /* Calculate levels for mip mapping */
1233 if (Levels == 0) {
1234 object->baseTexture.levels++;
1235 tmpW = Width;
1236 tmpH = Height;
1237 tmpD = Depth;
1238 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1239 tmpW = max(1, tmpW >> 1);
1240 tmpH = max(1, tmpH >> 1);
1241 tmpD = max(1, tmpD >> 1);
1242 object->baseTexture.levels++;
1244 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1247 /* Generate all the surfaces */
1248 tmpW = Width;
1249 tmpH = Height;
1250 tmpD = Depth;
1252 for (i = 0; i < object->baseTexture.levels; i++)
1254 /* Create the volume */
1255 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1256 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1258 /* Set it's container to this object */
1259 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1261 /* calcualte the next mipmap level */
1262 tmpW = max(1, tmpW >> 1);
1263 tmpH = max(1, tmpH >> 1);
1264 tmpD = max(1, tmpD >> 1);
1267 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1268 TRACE("(%p) : Created volume texture %p\n", This, object);
1269 return WINED3D_OK;
1272 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1273 UINT Width, UINT Height, UINT Depth,
1274 DWORD Usage,
1275 WINED3DFORMAT Format, WINED3DPOOL Pool,
1276 IWineD3DVolume** ppVolume,
1277 HANDLE* pSharedHandle, IUnknown *parent) {
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1280 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1281 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1283 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1285 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1286 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1288 object->currentDesc.Width = Width;
1289 object->currentDesc.Height = Height;
1290 object->currentDesc.Depth = Depth;
1291 object->bytesPerPixel = formatDesc->bpp;
1293 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1294 object->lockable = TRUE;
1295 object->locked = FALSE;
1296 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1297 object->dirty = TRUE;
1299 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1302 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1303 UINT Levels, DWORD Usage,
1304 WINED3DFORMAT Format, WINED3DPOOL Pool,
1305 IWineD3DCubeTexture **ppCubeTexture,
1306 HANDLE *pSharedHandle, IUnknown *parent,
1307 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1310 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1311 unsigned int i, j;
1312 UINT tmpW;
1313 HRESULT hr;
1314 unsigned int pow2EdgeLength = EdgeLength;
1316 /* TODO: It should only be possible to create textures for formats
1317 that are reported as supported */
1318 if (WINED3DFMT_UNKNOWN >= Format) {
1319 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1320 return WINED3DERR_INVALIDCALL;
1323 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1324 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1326 TRACE("(%p) Create Cube Texture\n", This);
1328 /** Non-power2 support **/
1330 /* Find the nearest pow2 match */
1331 pow2EdgeLength = 1;
1332 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1334 object->edgeLength = EdgeLength;
1335 /* TODO: support for native non-power 2 */
1336 /* Precalculated scaling for 'faked' non power of two texture coords */
1337 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1339 /* Calculate levels for mip mapping */
1340 if (Levels == 0) {
1341 object->baseTexture.levels++;
1342 tmpW = EdgeLength;
1343 while (tmpW > 1) {
1344 tmpW = max(1, tmpW >> 1);
1345 object->baseTexture.levels++;
1347 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1350 /* Generate all the surfaces */
1351 tmpW = EdgeLength;
1352 for (i = 0; i < object->baseTexture.levels; i++) {
1354 /* Create the 6 faces */
1355 for (j = 0; j < 6; j++) {
1357 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1358 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1360 if(hr!= WINED3D_OK) {
1361 /* clean up */
1362 int k;
1363 int l;
1364 for (l = 0; l < j; l++) {
1365 IWineD3DSurface_Release(object->surfaces[j][i]);
1367 for (k = 0; k < i; k++) {
1368 for (l = 0; l < 6; l++) {
1369 IWineD3DSurface_Release(object->surfaces[l][j]);
1373 FIXME("(%p) Failed to create surface\n",object);
1374 HeapFree(GetProcessHeap(),0,object);
1375 *ppCubeTexture = NULL;
1376 return hr;
1378 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1379 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1381 tmpW = max(1, tmpW >> 1);
1384 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1385 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1386 return WINED3D_OK;
1389 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1391 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1393 if (NULL == ppQuery) {
1394 /* Just a check to see if we support this type of query */
1395 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1396 switch(Type) {
1397 case WINED3DQUERYTYPE_OCCLUSION:
1398 TRACE("(%p) occlusion query\n", This);
1399 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1400 hr = WINED3D_OK;
1401 else
1402 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1403 break;
1404 case WINED3DQUERYTYPE_VCACHE:
1405 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1406 case WINED3DQUERYTYPE_VERTEXSTATS:
1407 case WINED3DQUERYTYPE_EVENT:
1408 case WINED3DQUERYTYPE_TIMESTAMP:
1409 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1410 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1411 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1412 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1413 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1414 case WINED3DQUERYTYPE_PIXELTIMINGS:
1415 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1416 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1417 default:
1418 FIXME("(%p) Unhandled query type %d\n", This, Type);
1420 return hr;
1423 D3DCREATEOBJECTINSTANCE(object, Query)
1424 object->type = Type;
1425 /* allocated the 'extended' data based on the type of query requested */
1426 switch(Type){
1427 case D3DQUERYTYPE_OCCLUSION:
1428 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1429 TRACE("(%p) Allocating data for an occlusion query\n", This);
1430 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1431 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1432 break;
1434 case D3DQUERYTYPE_VCACHE:
1435 case D3DQUERYTYPE_RESOURCEMANAGER:
1436 case D3DQUERYTYPE_VERTEXSTATS:
1437 case D3DQUERYTYPE_EVENT:
1438 case D3DQUERYTYPE_TIMESTAMP:
1439 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1440 case D3DQUERYTYPE_TIMESTAMPFREQ:
1441 case D3DQUERYTYPE_PIPELINETIMINGS:
1442 case D3DQUERYTYPE_INTERFACETIMINGS:
1443 case D3DQUERYTYPE_VERTEXTIMINGS:
1444 case D3DQUERYTYPE_PIXELTIMINGS:
1445 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1446 case D3DQUERYTYPE_CACHEUTILIZATION:
1447 default:
1448 object->extendedData = 0;
1449 FIXME("(%p) Unhandled query type %d\n",This , Type);
1451 TRACE("(%p) : Created Query %p\n", This, object);
1452 return WINED3D_OK;
1455 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1456 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1457 IUnknown* parent,
1458 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1459 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1462 HDC hDc;
1463 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1464 int num;
1465 XVisualInfo template;
1466 GLXContext oldContext;
1467 Drawable oldDrawable;
1468 HRESULT hr = WINED3D_OK;
1470 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1472 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1473 * does a device hold a reference to a swap chain giving them a lifetime of the device
1474 * or does the swap chain notify the device of its destruction.
1475 *******************************/
1477 /* Check the params */
1478 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1479 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1480 return WINED3DERR_INVALIDCALL;
1481 } else if (*pPresentationParameters->BackBufferCount > 1) {
1482 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");
1485 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1487 /*********************
1488 * Lookup the window Handle and the relating X window handle
1489 ********************/
1491 /* Setup hwnd we are using, plus which display this equates to */
1492 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1493 if (!object->win_handle) {
1494 object->win_handle = This->createParms.hFocusWindow;
1497 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1498 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1499 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1500 return WINED3DERR_NOTAVAILABLE;
1502 hDc = GetDC(object->win_handle);
1503 object->display = get_display(hDc);
1504 ReleaseDC(object->win_handle, hDc);
1505 TRACE("Using a display of %p %p\n", object->display, hDc);
1507 if (NULL == object->display || NULL == hDc) {
1508 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1509 return WINED3DERR_NOTAVAILABLE;
1512 if (object->win == 0) {
1513 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1514 return WINED3DERR_NOTAVAILABLE;
1517 * Create an opengl context for the display visual
1518 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1519 * use different properties after that point in time. FIXME: How to handle when requested format
1520 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1521 * it chooses is identical to the one already being used!
1522 **********************************/
1524 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1525 ENTER_GL();
1527 /* Create a new context for this swapchain */
1528 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1529 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1530 (or the best possible if none is requested) */
1531 TRACE("Found x visual ID : %ld\n", template.visualid);
1533 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1534 if (NULL == object->visInfo) {
1535 ERR("cannot really get XVisual\n");
1536 LEAVE_GL();
1537 return WINED3DERR_NOTAVAILABLE;
1538 } else {
1539 int n, value;
1540 /* Write out some debug info about the visual/s */
1541 TRACE("Using x visual ID : %ld\n", template.visualid);
1542 TRACE(" visual info: %p\n", object->visInfo);
1543 TRACE(" num items : %d\n", num);
1544 for (n = 0;n < num; n++) {
1545 TRACE("=====item=====: %d\n", n + 1);
1546 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1547 TRACE(" screen : %d\n", object->visInfo[n].screen);
1548 TRACE(" depth : %u\n", object->visInfo[n].depth);
1549 TRACE(" class : %d\n", object->visInfo[n].class);
1550 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1551 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1552 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1553 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1554 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1555 /* log some extra glx info */
1556 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1557 TRACE(" gl_aux_buffers : %d\n", value);
1558 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1559 TRACE(" gl_buffer_size : %d\n", value);
1560 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1561 TRACE(" gl_red_size : %d\n", value);
1562 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1563 TRACE(" gl_green_size : %d\n", value);
1564 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1565 TRACE(" gl_blue_size : %d\n", value);
1566 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1567 TRACE(" gl_alpha_size : %d\n", value);
1568 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1569 TRACE(" gl_depth_size : %d\n", value);
1570 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1571 TRACE(" gl_stencil_size : %d\n", value);
1573 /* Now choose a simila visual ID*/
1575 #ifdef USE_CONTEXT_MANAGER
1577 /** TODO: use a context mamager **/
1578 #endif
1581 IWineD3DSwapChain *implSwapChain;
1582 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1583 /* The first time around we create the context that is shared with all other swapchains and render targets */
1584 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1585 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1586 } else {
1588 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1589 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1590 /* and create a new context with the implicit swapchains context as the shared context */
1591 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1592 IWineD3DSwapChain_Release(implSwapChain);
1596 /* Cleanup */
1597 XFree(object->visInfo);
1598 object->visInfo = NULL;
1600 LEAVE_GL();
1602 if (!object->glCtx) {
1603 ERR("Failed to create GLX context\n");
1604 return WINED3DERR_NOTAVAILABLE;
1605 } else {
1606 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1607 object->win_handle, object->glCtx, object->win, object->visInfo);
1610 /*********************
1611 * Windowed / Fullscreen
1612 *******************/
1615 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1616 * so we should really check to see if there is a fullscreen swapchain already
1617 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1618 **************************************/
1620 if (!*(pPresentationParameters->Windowed)) {
1622 DEVMODEW devmode;
1623 HDC hdc;
1624 int bpp = 0;
1626 /* Get info on the current display setup */
1627 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1628 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1629 DeleteDC(hdc);
1631 /* Change the display settings */
1632 memset(&devmode, 0, sizeof(DEVMODEW));
1633 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1634 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1635 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1636 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1637 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1638 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1640 /* Make popup window */
1641 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1642 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1643 *(pPresentationParameters->BackBufferWidth),
1644 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1646 /* For GetDisplayMode */
1647 This->ddraw_width = devmode.dmPelsWidth;
1648 This->ddraw_height = devmode.dmPelsHeight;
1649 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1653 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1654 * then the corresponding dimension of the client area of the hDeviceWindow
1655 * (or the focus window, if hDeviceWindow is NULL) is taken.
1656 **********************/
1658 if (*(pPresentationParameters->Windowed) &&
1659 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1660 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1662 RECT Rect;
1663 GetClientRect(object->win_handle, &Rect);
1665 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1666 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1667 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1669 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1670 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1671 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1675 /*********************
1676 * finish off parameter initialization
1677 *******************/
1679 /* Put the correct figures in the presentation parameters */
1680 TRACE("Coppying accross presentaion paraneters\n");
1681 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1682 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1683 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1684 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1685 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1686 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1687 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1688 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1689 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1690 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1691 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1692 object->presentParms.Flags = *(pPresentationParameters->Flags);
1693 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1694 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1697 /*********************
1698 * Create the back, front and stencil buffers
1699 *******************/
1701 TRACE("calling rendertarget CB\n");
1702 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1703 object->presentParms.BackBufferWidth,
1704 object->presentParms.BackBufferHeight,
1705 object->presentParms.BackBufferFormat,
1706 object->presentParms.MultiSampleType,
1707 object->presentParms.MultiSampleQuality,
1708 TRUE /* Lockable */,
1709 &object->frontBuffer,
1710 NULL /* pShared (always null)*/);
1711 if (object->frontBuffer != NULL)
1712 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1714 if(object->presentParms.BackBufferCount > 0) {
1715 int i;
1717 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1718 if(!object->backBuffer) {
1719 ERR("Out of memory\n");
1721 if (object->frontBuffer) {
1722 IUnknown *bufferParent;
1723 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1724 IUnknown_Release(bufferParent); /* once for the get parent */
1725 if (IUnknown_Release(bufferParent) > 0) {
1726 FIXME("(%p) Something's still holding the front buffer\n",This);
1729 HeapFree(GetProcessHeap(), 0, object);
1730 return E_OUTOFMEMORY;
1733 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1734 TRACE("calling rendertarget CB\n");
1735 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1736 object->presentParms.BackBufferWidth,
1737 object->presentParms.BackBufferHeight,
1738 object->presentParms.BackBufferFormat,
1739 object->presentParms.MultiSampleType,
1740 object->presentParms.MultiSampleQuality,
1741 TRUE /* Lockable */,
1742 &object->backBuffer[i],
1743 NULL /* pShared (always null)*/);
1744 if(hr == WINED3D_OK && object->backBuffer[i]) {
1745 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1746 } else {
1747 break;
1750 } else {
1751 object->backBuffer = NULL;
1754 if (object->backBuffer != NULL) {
1755 ENTER_GL();
1756 glDrawBuffer(GL_BACK);
1757 checkGLcall("glDrawBuffer(GL_BACK)");
1758 LEAVE_GL();
1759 } else {
1760 /* Single buffering - draw to front buffer */
1761 ENTER_GL();
1762 glDrawBuffer(GL_FRONT);
1763 checkGLcall("glDrawBuffer(GL_FRONT)");
1764 LEAVE_GL();
1767 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1768 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1769 TRACE("Creating depth stencil buffer\n");
1770 if (This->depthStencilBuffer == NULL ) {
1771 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1772 object->presentParms.BackBufferWidth,
1773 object->presentParms.BackBufferHeight,
1774 object->presentParms.AutoDepthStencilFormat,
1775 object->presentParms.MultiSampleType,
1776 object->presentParms.MultiSampleQuality,
1777 FALSE /* FIXME: Discard */,
1778 &This->depthStencilBuffer,
1779 NULL /* pShared (always null)*/ );
1780 if (This->depthStencilBuffer != NULL)
1781 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1784 /** TODO: A check on width, height and multisample types
1785 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1786 ****************************/
1787 object->wantsDepthStencilBuffer = TRUE;
1788 } else {
1789 object->wantsDepthStencilBuffer = FALSE;
1792 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1795 /*********************
1796 * init the default renderTarget management
1797 *******************/
1798 object->drawable = object->win;
1799 object->render_ctx = object->glCtx;
1801 if (hr == WINED3D_OK) {
1802 /*********************
1803 * Setup some defaults and clear down the buffers
1804 *******************/
1805 ENTER_GL();
1806 /** save current context and drawable **/
1807 oldContext = glXGetCurrentContext();
1808 oldDrawable = glXGetCurrentDrawable();
1810 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1811 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1812 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1814 checkGLcall("glXMakeCurrent");
1816 TRACE("Setting up the screen\n");
1817 /* Clear the screen */
1818 glClearColor(1.0, 0.0, 0.0, 0.0);
1819 checkGLcall("glClearColor");
1820 glClearIndex(0);
1821 glClearDepth(1);
1822 glClearStencil(0xffff);
1824 checkGLcall("glClear");
1826 glColor3f(1.0, 1.0, 1.0);
1827 checkGLcall("glColor3f");
1829 glEnable(GL_LIGHTING);
1830 checkGLcall("glEnable");
1832 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1833 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1835 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1836 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1838 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1839 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1841 /* switch back to the original context (if there was one)*/
1842 if (This->swapchains) {
1843 /** TODO: restore the context and drawable **/
1844 glXMakeCurrent(object->display, oldDrawable, oldContext);
1847 LEAVE_GL();
1849 TRACE("Set swapchain to %p\n", object);
1850 } else { /* something went wrong so clean up */
1851 IUnknown* bufferParent;
1852 if (object->frontBuffer) {
1854 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1855 IUnknown_Release(bufferParent); /* once for the get parent */
1856 if (IUnknown_Release(bufferParent) > 0) {
1857 FIXME("(%p) Something's still holding the front buffer\n",This);
1860 if (object->backBuffer) {
1861 int i;
1862 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1863 if(object->backBuffer[i]) {
1864 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1865 IUnknown_Release(bufferParent); /* once for the get parent */
1866 if (IUnknown_Release(bufferParent) > 0) {
1867 FIXME("(%p) Something's still holding the back buffer\n",This);
1871 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1872 object->backBuffer = NULL;
1874 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1875 /* Clean up the context */
1876 /* check that we are the current context first (we shouldn't be though!) */
1877 if (object->glCtx != 0) {
1878 if(glXGetCurrentContext() == object->glCtx) {
1879 glXMakeCurrent(object->display, None, NULL);
1881 glXDestroyContext(object->display, object->glCtx);
1883 HeapFree(GetProcessHeap(), 0, object);
1887 return hr;
1890 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1891 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 TRACE("(%p)\n", This);
1895 return This->NumberOfSwapChains;
1898 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1900 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1902 if(iSwapChain < This->NumberOfSwapChains) {
1903 *pSwapChain = This->swapchains[iSwapChain];
1904 IWineD3DSwapChain_AddRef(*pSwapChain);
1905 TRACE("(%p) returning %p\n", This, *pSwapChain);
1906 return WINED3D_OK;
1907 } else {
1908 TRACE("Swapchain out of range\n");
1909 *pSwapChain = NULL;
1910 return WINED3DERR_INVALIDCALL;
1914 /*****
1915 * Vertex Declaration
1916 *****/
1917 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1919 IWineD3DVertexDeclarationImpl *object = NULL;
1920 HRESULT hr = WINED3D_OK;
1921 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1922 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1923 object->allFVF = 0;
1925 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1927 return hr;
1930 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1931 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1933 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1934 HRESULT hr = WINED3D_OK;
1935 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1936 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1938 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1940 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1941 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1942 if (pDeclaration != NULL) {
1943 IWineD3DVertexDeclaration *vertexDeclaration;
1944 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1945 if (WINED3D_OK == hr) {
1946 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1947 object->vertexDeclaration = vertexDeclaration;
1948 } else {
1949 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1950 IWineD3DVertexShader_Release(*ppVertexShader);
1951 return WINED3DERR_INVALIDCALL;
1955 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1957 if (WINED3D_OK != hr) {
1958 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1959 IWineD3DVertexShader_Release(*ppVertexShader);
1960 return WINED3DERR_INVALIDCALL;
1963 #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. */
1964 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1965 /* Foo */
1966 } else {
1967 /* Bar */
1970 #endif
1972 return WINED3D_OK;
1975 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1977 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1978 HRESULT hr = WINED3D_OK;
1980 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1981 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1982 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1983 if (WINED3D_OK == hr) {
1984 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1985 } else {
1986 WARN("(%p) : Failed to create pixel shader\n", This);
1989 return hr;
1992 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1994 IWineD3DPaletteImpl *object;
1995 HRESULT hr;
1996 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1998 /* Create the new object */
1999 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2000 if(!object) {
2001 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2002 return E_OUTOFMEMORY;
2005 object->lpVtbl = &IWineD3DPalette_Vtbl;
2006 object->ref = 1;
2007 object->Flags = Flags;
2008 object->parent = Parent;
2009 object->wineD3DDevice = This;
2010 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2012 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2014 if(!object->hpal) {
2015 HeapFree( GetProcessHeap(), 0, object);
2016 return E_OUTOFMEMORY;
2019 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2020 if(FAILED(hr)) {
2021 IWineD3DPalette_Release((IWineD3DPalette *) object);
2022 return hr;
2025 *Palette = (IWineD3DPalette *) object;
2027 return WINED3D_OK;
2030 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2032 IWineD3DSwapChainImpl *swapchain;
2034 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2035 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2037 /* TODO: Test if OpenGL is compiled in and loaded */
2039 /* Setup the implicit swapchain */
2040 TRACE("Creating implicit swapchain\n");
2041 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2042 WARN("Failed to create implicit swapchain\n");
2043 return WINED3DERR_INVALIDCALL;
2046 This->NumberOfSwapChains = 1;
2047 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2048 if(!This->swapchains) {
2049 ERR("Out of memory!\n");
2050 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2051 return E_OUTOFMEMORY;
2053 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2055 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2056 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2057 This->renderTarget = swapchain->backBuffer[0];
2059 else {
2060 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2061 This->renderTarget = swapchain->frontBuffer;
2063 IWineD3DSurface_AddRef(This->renderTarget);
2064 /* Depth Stencil support */
2065 This->stencilBufferTarget = This->depthStencilBuffer;
2066 if (NULL != This->stencilBufferTarget) {
2067 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2070 /* Set up some starting GL setup */
2071 ENTER_GL();
2073 * Initialize openGL extension related variables
2074 * with Default values
2077 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2078 /* Setup all the devices defaults */
2079 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2080 #if 0
2081 IWineD3DImpl_CheckGraphicsMemory();
2082 #endif
2083 LEAVE_GL();
2085 /* Initialize our list of GLSL programs */
2086 list_init(&This->glsl_shader_progs);
2088 { /* Set a default viewport */
2089 D3DVIEWPORT9 vp;
2090 vp.X = 0;
2091 vp.Y = 0;
2092 vp.Width = *(pPresentationParameters->BackBufferWidth);
2093 vp.Height = *(pPresentationParameters->BackBufferHeight);
2094 vp.MinZ = 0.0f;
2095 vp.MaxZ = 1.0f;
2096 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2099 /* Initialize the current view state */
2100 This->modelview_valid = 1;
2101 This->proj_valid = 0;
2102 This->view_ident = 1;
2103 This->last_was_rhw = 0;
2104 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2105 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2107 /* Clear the screen */
2108 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2110 This->d3d_initialized = TRUE;
2111 return WINED3D_OK;
2114 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2116 int sampler;
2117 IUnknown* stencilBufferParent;
2118 IUnknown* swapChainParent;
2119 uint i;
2120 TRACE("(%p)\n", This);
2122 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2124 /* Delete the mouse cursor texture */
2125 if(This->cursorTexture) {
2126 ENTER_GL();
2127 glDeleteTextures(1, &This->cursorTexture);
2128 LEAVE_GL();
2129 This->cursorTexture = 0;
2132 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2133 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2136 /* Release the buffers (with sanity checks)*/
2137 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2138 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2139 if(This->depthStencilBuffer != This->stencilBufferTarget)
2140 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2142 This->stencilBufferTarget = NULL;
2144 TRACE("Releasing the render target at %p\n", This->renderTarget);
2145 if(IWineD3DSurface_Release(This->renderTarget) >0){
2146 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2148 TRACE("Setting rendertarget to NULL\n");
2149 This->renderTarget = NULL;
2151 if (This->depthStencilBuffer) {
2152 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2153 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2154 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2155 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2157 This->depthStencilBuffer = NULL;
2160 for(i=0; i < This->NumberOfSwapChains; i++) {
2161 TRACE("Releasing the implicit swapchain %d\n", i);
2162 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2163 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2164 IUnknown_Release(swapChainParent); /* once for the get parent */
2165 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2166 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2170 HeapFree(GetProcessHeap(), 0, This->swapchains);
2171 This->swapchains = NULL;
2172 This->NumberOfSwapChains = 0;
2174 This->d3d_initialized = FALSE;
2175 return WINED3D_OK;
2178 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2181 DEVMODEW DevModeW;
2182 int i;
2183 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2185 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2187 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2188 /* Ignore some modes if a description was passed */
2189 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2190 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2191 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2193 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2195 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2196 return D3D_OK;
2199 return D3D_OK;
2202 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2203 DEVMODEW devmode;
2204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2205 LONG ret;
2206 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2208 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2210 /* Resize the screen even without a window:
2211 * The app could have unset it with SetCooperativeLevel, but not called
2212 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2213 * but we don't have any hwnd
2216 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2217 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2218 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2219 devmode.dmPelsWidth = pMode->Width;
2220 devmode.dmPelsHeight = pMode->Height;
2222 devmode.dmDisplayFrequency = pMode->RefreshRate;
2223 if (pMode->RefreshRate != 0) {
2224 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2227 /* Only change the mode if necessary */
2228 if( (This->ddraw_width == pMode->Width) &&
2229 (This->ddraw_height == pMode->Height) &&
2230 (This->ddraw_format == pMode->Format) &&
2231 (pMode->RefreshRate == 0) ) {
2232 return D3D_OK;
2235 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2236 if (ret != DISP_CHANGE_SUCCESSFUL) {
2237 if(devmode.dmDisplayFrequency != 0) {
2238 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2239 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2240 devmode.dmDisplayFrequency = 0;
2241 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2243 if(ret != DISP_CHANGE_SUCCESSFUL) {
2244 return DDERR_INVALIDMODE;
2248 /* Store the new values */
2249 This->ddraw_width = pMode->Width;
2250 This->ddraw_height = pMode->Height;
2251 This->ddraw_format = pMode->Format;
2253 /* Only do this with a window of course */
2254 if(This->ddraw_window)
2255 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2257 return WINED3D_OK;
2260 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2262 *ppD3D= This->wineD3D;
2263 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2264 IWineD3D_AddRef(*ppD3D);
2265 return WINED3D_OK;
2268 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2269 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2270 * Into the video ram as possible and seeing how many fit
2271 * you can also get the correct initial value from nvidia and ATI's driver via X
2272 * texture memory is video memory + AGP memory
2273 *******************/
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2275 static BOOL showfixmes = TRUE;
2276 if (showfixmes) {
2277 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2278 (wined3d_settings.emulated_textureram/(1024*1024)),
2279 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2280 showfixmes = FALSE;
2282 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2283 (wined3d_settings.emulated_textureram/(1024*1024)),
2284 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2285 /* return simulated texture memory left */
2286 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2291 /*****
2292 * Get / Set FVF
2293 *****/
2294 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2296 HRESULT hr = WINED3D_OK;
2298 /* Update the current state block */
2299 This->updateStateBlock->fvf = fvf;
2300 This->updateStateBlock->changed.fvf = TRUE;
2301 This->updateStateBlock->set.fvf = TRUE;
2303 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2304 return hr;
2308 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2310 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2311 *pfvf = This->stateBlock->fvf;
2312 return WINED3D_OK;
2315 /*****
2316 * Get / Set Stream Source
2317 *****/
2318 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 IWineD3DVertexBuffer *oldSrc;
2322 /**TODO: instance and index data, see
2323 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2325 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2326 **************/
2328 /* D3d9 only, but shouldn't hurt d3d8 */
2329 UINT streamFlags;
2331 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2332 if (streamFlags) {
2333 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2334 FIXME("stream index data not supported\n");
2336 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2337 FIXME("stream instance data not supported\n");
2341 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2343 if (StreamNumber >= MAX_STREAMS) {
2344 WARN("Stream out of range %d\n", StreamNumber);
2345 return WINED3DERR_INVALIDCALL;
2348 oldSrc = This->stateBlock->streamSource[StreamNumber];
2349 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2351 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2352 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2353 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2354 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2355 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2356 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2358 /* Handle recording of state blocks */
2359 if (This->isRecordingState) {
2360 TRACE("Recording... not performing anything\n");
2361 return WINED3D_OK;
2364 /* Same stream object: no action */
2365 if (oldSrc == pStreamData)
2366 return WINED3D_OK;
2368 /* Need to do a getParent and pass the reffs up */
2369 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2370 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2371 so for now, just count internally */
2372 if (pStreamData != NULL) {
2373 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2374 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2375 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2377 vbImpl->stream = StreamNumber;
2378 vbImpl->Flags |= VBFLAG_STREAM;
2379 IWineD3DVertexBuffer_AddRef(pStreamData);
2381 if (oldSrc != NULL) {
2382 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2383 IWineD3DVertexBuffer_Release(oldSrc);
2386 return WINED3D_OK;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 UINT streamFlags;
2393 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2394 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2397 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2398 if (streamFlags) {
2399 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2400 FIXME("stream index data not supported\n");
2402 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2403 FIXME("stream instance data not supported\n");
2407 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2409 if (StreamNumber >= MAX_STREAMS) {
2410 WARN("Stream out of range %d\n", StreamNumber);
2411 return WINED3DERR_INVALIDCALL;
2413 *pStream = This->stateBlock->streamSource[StreamNumber];
2414 *pStride = This->stateBlock->streamStride[StreamNumber];
2415 if (pOffset) {
2416 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2419 if (*pStream == NULL) {
2420 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2421 return WINED3DERR_INVALIDCALL;
2424 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2425 return WINED3D_OK;
2428 /*Should be quite easy, just an extension of vertexdata
2429 ref...
2430 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2432 The divider is a bit odd though
2434 VertexOffset = StartVertex / Divider * StreamStride +
2435 VertexIndex / Divider * StreamStride + StreamOffset
2438 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2441 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2442 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2444 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2445 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2446 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2448 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2449 FIXME("Stream indexing not fully supported\n");
2452 return WINED3D_OK;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2459 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2461 TRACE("(%p) : returning %d\n", This, *Divider);
2463 return WINED3D_OK;
2466 /*****
2467 * Get / Set & Multiply Transform
2468 *****/
2469 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 /* Most of this routine, comments included copied from ddraw tree initially: */
2473 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2475 /* Handle recording of state blocks */
2476 if (This->isRecordingState) {
2477 TRACE("Recording... not performing anything\n");
2478 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2479 This->updateStateBlock->set.transform[d3dts] = TRUE;
2480 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2481 return WINED3D_OK;
2485 * If the new matrix is the same as the current one,
2486 * we cut off any further processing. this seems to be a reasonable
2487 * optimization because as was noticed, some apps (warcraft3 for example)
2488 * tend towards setting the same matrix repeatedly for some reason.
2490 * From here on we assume that the new matrix is different, wherever it matters.
2492 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2493 TRACE("The app is setting the same matrix over again\n");
2494 return WINED3D_OK;
2495 } else {
2496 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2500 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2501 where ViewMat = Camera space, WorldMat = world space.
2503 In OpenGL, camera and world space is combined into GL_MODELVIEW
2504 matrix. The Projection matrix stay projection matrix.
2507 /* Capture the times we can just ignore the change for now */
2508 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2509 This->modelview_valid = FALSE;
2510 return WINED3D_OK;
2512 } else if (d3dts == WINED3DTS_PROJECTION) {
2513 This->proj_valid = FALSE;
2514 return WINED3D_OK;
2516 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2517 /* Indexed Vertex Blending Matrices 256 -> 511 */
2518 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2519 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2520 return WINED3D_OK;
2523 /* Now we really are going to have to change a matrix */
2524 ENTER_GL();
2526 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2527 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2528 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2529 unsigned int k;
2531 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2532 * NOTE: We have to reset the positions even if the light/plane is not currently
2533 * enabled, since the call to enable it will not reset the position.
2534 * NOTE2: Apparently texture transforms do NOT need reapplying
2537 PLIGHTINFOEL *lightChain = NULL;
2538 This->modelview_valid = FALSE;
2539 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2541 glMatrixMode(GL_MODELVIEW);
2542 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2543 glPushMatrix();
2544 glLoadMatrixf((float *)lpmatrix);
2545 checkGLcall("glLoadMatrixf(...)");
2547 /* Reset lights */
2548 lightChain = This->stateBlock->lights;
2549 while (lightChain && lightChain->glIndex != -1) {
2550 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2551 checkGLcall("glLightfv posn");
2552 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2553 checkGLcall("glLightfv dirn");
2554 lightChain = lightChain->next;
2557 /* Reset Clipping Planes if clipping is enabled */
2558 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2559 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2560 checkGLcall("glClipPlane");
2562 glPopMatrix();
2564 } else { /* What was requested!?? */
2565 WARN("invalid matrix specified: %i\n", d3dts);
2568 /* Release lock, all done */
2569 LEAVE_GL();
2570 return WINED3D_OK;
2573 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2575 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2576 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2577 return WINED3D_OK;
2580 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2581 D3DMATRIX *mat = NULL;
2582 D3DMATRIX temp;
2584 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2585 * below means it will be recorded in a state block change, but it
2586 * works regardless where it is recorded.
2587 * If this is found to be wrong, change to StateBlock.
2589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2590 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2592 if (State < HIGHEST_TRANSFORMSTATE)
2594 mat = &This->updateStateBlock->transforms[State];
2595 } else {
2596 FIXME("Unhandled transform state!!\n");
2599 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2601 /* Apply change via set transform - will reapply to eg. lights this way */
2602 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2605 /*****
2606 * Get / Set Light
2607 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2608 *****/
2609 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2610 you can reference any indexes you want as long as that number max are enabled at any
2611 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2612 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2613 but when recording, just build a chain pretty much of commands to be replayed. */
2615 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2616 float rho;
2617 PLIGHTINFOEL *object, *temp;
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2620 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2622 /* If recording state block, just add to end of lights chain */
2623 if (This->isRecordingState) {
2624 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2625 if (NULL == object) {
2626 return WINED3DERR_OUTOFVIDEOMEMORY;
2628 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2629 object->OriginalIndex = Index;
2630 object->glIndex = -1;
2631 object->changed = TRUE;
2633 /* Add to the END of the chain of lights changes to be replayed */
2634 if (This->updateStateBlock->lights == NULL) {
2635 This->updateStateBlock->lights = object;
2636 } else {
2637 temp = This->updateStateBlock->lights;
2638 while (temp->next != NULL) temp=temp->next;
2639 temp->next = object;
2641 TRACE("Recording... not performing anything more\n");
2642 return WINED3D_OK;
2645 /* Ok, not recording any longer so do real work */
2646 object = This->stateBlock->lights;
2647 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2649 /* If we didn't find it in the list of lights, time to add it */
2650 if (object == NULL) {
2651 PLIGHTINFOEL *insertAt,*prevPos;
2653 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2654 if (NULL == object) {
2655 return WINED3DERR_OUTOFVIDEOMEMORY;
2657 object->OriginalIndex = Index;
2658 object->glIndex = -1;
2660 /* Add it to the front of list with the idea that lights will be changed as needed
2661 BUT after any lights currently assigned GL indexes */
2662 insertAt = This->stateBlock->lights;
2663 prevPos = NULL;
2664 while (insertAt != NULL && insertAt->glIndex != -1) {
2665 prevPos = insertAt;
2666 insertAt = insertAt->next;
2669 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2670 This->stateBlock->lights = object;
2671 } else if (insertAt == NULL) { /* End of list */
2672 prevPos->next = object;
2673 object->prev = prevPos;
2674 } else { /* Middle of chain */
2675 if (prevPos == NULL) {
2676 This->stateBlock->lights = object;
2677 } else {
2678 prevPos->next = object;
2680 object->prev = prevPos;
2681 object->next = insertAt;
2682 insertAt->prev = object;
2686 /* Initialize the object */
2687 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,
2688 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2689 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2690 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2691 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2692 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2693 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2695 /* Save away the information */
2696 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2698 switch (pLight->Type) {
2699 case D3DLIGHT_POINT:
2700 /* Position */
2701 object->lightPosn[0] = pLight->Position.x;
2702 object->lightPosn[1] = pLight->Position.y;
2703 object->lightPosn[2] = pLight->Position.z;
2704 object->lightPosn[3] = 1.0f;
2705 object->cutoff = 180.0f;
2706 /* FIXME: Range */
2707 break;
2709 case D3DLIGHT_DIRECTIONAL:
2710 /* Direction */
2711 object->lightPosn[0] = -pLight->Direction.x;
2712 object->lightPosn[1] = -pLight->Direction.y;
2713 object->lightPosn[2] = -pLight->Direction.z;
2714 object->lightPosn[3] = 0.0;
2715 object->exponent = 0.0f;
2716 object->cutoff = 180.0f;
2717 break;
2719 case D3DLIGHT_SPOT:
2720 /* Position */
2721 object->lightPosn[0] = pLight->Position.x;
2722 object->lightPosn[1] = pLight->Position.y;
2723 object->lightPosn[2] = pLight->Position.z;
2724 object->lightPosn[3] = 1.0;
2726 /* Direction */
2727 object->lightDirn[0] = pLight->Direction.x;
2728 object->lightDirn[1] = pLight->Direction.y;
2729 object->lightDirn[2] = pLight->Direction.z;
2730 object->lightDirn[3] = 1.0;
2733 * opengl-ish and d3d-ish spot lights use too different models for the
2734 * light "intensity" as a function of the angle towards the main light direction,
2735 * so we only can approximate very roughly.
2736 * however spot lights are rather rarely used in games (if ever used at all).
2737 * furthermore if still used, probably nobody pays attention to such details.
2739 if (pLight->Falloff == 0) {
2740 rho = 6.28f;
2741 } else {
2742 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2744 if (rho < 0.0001) rho = 0.0001f;
2745 object->exponent = -0.3/log(cos(rho/2));
2746 object->cutoff = pLight->Phi*90/M_PI;
2748 /* FIXME: Range */
2749 break;
2751 default:
2752 FIXME("Unrecognized light type %d\n", pLight->Type);
2755 /* Update the live definitions if the light is currently assigned a glIndex */
2756 if (object->glIndex != -1) {
2757 setup_light(iface, object->glIndex, object);
2759 return WINED3D_OK;
2762 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2763 PLIGHTINFOEL *lightInfo = NULL;
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2767 /* Locate the light in the live lights */
2768 lightInfo = This->stateBlock->lights;
2769 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2771 if (lightInfo == NULL) {
2772 TRACE("Light information requested but light not defined\n");
2773 return WINED3DERR_INVALIDCALL;
2776 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2777 return WINED3D_OK;
2780 /*****
2781 * Get / Set Light Enable
2782 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2783 *****/
2784 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2785 PLIGHTINFOEL *lightInfo = NULL;
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2789 /* Tests show true = 128...not clear why */
2791 Enable = Enable? 128: 0;
2793 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2794 if (This->isRecordingState) {
2795 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2796 if (NULL == lightInfo) {
2797 return WINED3DERR_OUTOFVIDEOMEMORY;
2799 lightInfo->OriginalIndex = Index;
2800 lightInfo->glIndex = -1;
2801 lightInfo->enabledChanged = TRUE;
2802 lightInfo->lightEnabled = Enable;
2804 /* Add to the END of the chain of lights changes to be replayed */
2805 if (This->updateStateBlock->lights == NULL) {
2806 This->updateStateBlock->lights = lightInfo;
2807 } else {
2808 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2809 while (temp->next != NULL) temp=temp->next;
2810 temp->next = lightInfo;
2812 TRACE("Recording... not performing anything more\n");
2813 return WINED3D_OK;
2816 /* Not recording... So, locate the light in the live lights */
2817 lightInfo = This->stateBlock->lights;
2818 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2820 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2821 if (lightInfo == NULL) {
2823 TRACE("Light enabled requested but light not defined, so defining one!\n");
2824 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2826 /* Search for it again! Should be fairly quick as near head of list */
2827 lightInfo = This->stateBlock->lights;
2828 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2829 if (lightInfo == NULL) {
2830 FIXME("Adding default lights has failed dismally\n");
2831 return WINED3DERR_INVALIDCALL;
2835 /* OK, we now have a light... */
2836 if (Enable == FALSE) {
2838 /* If we are disabling it, check it was enabled, and
2839 still only do something if it has assigned a glIndex (which it should have!) */
2840 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2841 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2842 ENTER_GL();
2843 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2844 checkGLcall("glDisable GL_LIGHT0+Index");
2845 LEAVE_GL();
2846 } else {
2847 TRACE("Nothing to do as light was not enabled\n");
2849 lightInfo->lightEnabled = Enable;
2850 } else {
2852 /* We are enabling it. If it is enabled, it's really simple */
2853 if (lightInfo->lightEnabled) {
2854 /* nop */
2855 TRACE("Nothing to do as light was enabled\n");
2857 /* If it already has a glIndex, it's still simple */
2858 } else if (lightInfo->glIndex != -1) {
2859 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2860 lightInfo->lightEnabled = Enable;
2861 ENTER_GL();
2862 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2863 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2864 LEAVE_GL();
2866 /* Otherwise got to find space - lights are ordered gl indexes first */
2867 } else {
2868 PLIGHTINFOEL *bsf = NULL;
2869 PLIGHTINFOEL *pos = This->stateBlock->lights;
2870 PLIGHTINFOEL *prev = NULL;
2871 int Index= 0;
2872 int glIndex = -1;
2874 /* Try to minimize changes as much as possible */
2875 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2877 /* Try to remember which index can be replaced if necessary */
2878 if (bsf==NULL && pos->lightEnabled == FALSE) {
2879 /* Found a light we can replace, save as best replacement */
2880 bsf = pos;
2883 /* Step to next space */
2884 prev = pos;
2885 pos = pos->next;
2886 Index ++;
2889 /* If we have too many active lights, fail the call */
2890 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2891 FIXME("Program requests too many concurrent lights\n");
2892 return WINED3DERR_INVALIDCALL;
2894 /* If we have allocated all lights, but not all are enabled,
2895 reuse one which is not enabled */
2896 } else if (Index == This->maxConcurrentLights) {
2897 /* use bsf - Simply swap the new light and the BSF one */
2898 PLIGHTINFOEL *bsfNext = bsf->next;
2899 PLIGHTINFOEL *bsfPrev = bsf->prev;
2901 /* Sort out ends */
2902 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2903 if (bsf->prev != NULL) {
2904 bsf->prev->next = lightInfo;
2905 } else {
2906 This->stateBlock->lights = lightInfo;
2909 /* If not side by side, lots of chains to update */
2910 if (bsf->next != lightInfo) {
2911 lightInfo->prev->next = bsf;
2912 bsf->next->prev = lightInfo;
2913 bsf->next = lightInfo->next;
2914 bsf->prev = lightInfo->prev;
2915 lightInfo->next = bsfNext;
2916 lightInfo->prev = bsfPrev;
2918 } else {
2919 /* Simple swaps */
2920 bsf->prev = lightInfo;
2921 bsf->next = lightInfo->next;
2922 lightInfo->next = bsf;
2923 lightInfo->prev = bsfPrev;
2927 /* Update states */
2928 glIndex = bsf->glIndex;
2929 bsf->glIndex = -1;
2930 lightInfo->glIndex = glIndex;
2931 lightInfo->lightEnabled = Enable;
2933 /* Finally set up the light in gl itself */
2934 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2935 ENTER_GL();
2936 setup_light(iface, glIndex, lightInfo);
2937 glEnable(GL_LIGHT0 + glIndex);
2938 checkGLcall("glEnable GL_LIGHT0 new setup");
2939 LEAVE_GL();
2941 /* If we reached the end of the allocated lights, with space in the
2942 gl lights, setup a new light */
2943 } else if (pos->glIndex == -1) {
2945 /* We reached the end of the allocated gl lights, so already
2946 know the index of the next one! */
2947 glIndex = Index;
2948 lightInfo->glIndex = glIndex;
2949 lightInfo->lightEnabled = Enable;
2951 /* In an ideal world, it's already in the right place */
2952 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2953 /* No need to move it */
2954 } else {
2955 /* Remove this light from the list */
2956 lightInfo->prev->next = lightInfo->next;
2957 if (lightInfo->next != NULL) {
2958 lightInfo->next->prev = lightInfo->prev;
2961 /* Add in at appropriate place (inbetween prev and pos) */
2962 lightInfo->prev = prev;
2963 lightInfo->next = pos;
2964 if (prev == NULL) {
2965 This->stateBlock->lights = lightInfo;
2966 } else {
2967 prev->next = lightInfo;
2969 if (pos != NULL) {
2970 pos->prev = lightInfo;
2974 /* Finally set up the light in gl itself */
2975 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2976 ENTER_GL();
2977 setup_light(iface, glIndex, lightInfo);
2978 glEnable(GL_LIGHT0 + glIndex);
2979 checkGLcall("glEnable GL_LIGHT0 new setup");
2980 LEAVE_GL();
2985 return WINED3D_OK;
2988 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2990 PLIGHTINFOEL *lightInfo = NULL;
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 TRACE("(%p) : for idx(%ld)\n", This, Index);
2994 /* Locate the light in the live lights */
2995 lightInfo = This->stateBlock->lights;
2996 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2998 if (lightInfo == NULL) {
2999 TRACE("Light enabled state requested but light not defined\n");
3000 return WINED3DERR_INVALIDCALL;
3002 *pEnable = lightInfo->lightEnabled;
3003 return WINED3D_OK;
3006 /*****
3007 * Get / Set Clip Planes
3008 *****/
3009 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3013 /* Validate Index */
3014 if (Index >= GL_LIMITS(clipplanes)) {
3015 TRACE("Application has requested clipplane this device doesn't support\n");
3016 return WINED3DERR_INVALIDCALL;
3019 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3020 This->updateStateBlock->set.clipplane[Index] = TRUE;
3021 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3022 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3023 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3024 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3026 /* Handle recording of state blocks */
3027 if (This->isRecordingState) {
3028 TRACE("Recording... not performing anything\n");
3029 return WINED3D_OK;
3032 /* Apply it */
3034 ENTER_GL();
3036 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3037 glMatrixMode(GL_MODELVIEW);
3038 glPushMatrix();
3039 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3041 TRACE("Clipplane [%f,%f,%f,%f]\n",
3042 This->updateStateBlock->clipplane[Index][0],
3043 This->updateStateBlock->clipplane[Index][1],
3044 This->updateStateBlock->clipplane[Index][2],
3045 This->updateStateBlock->clipplane[Index][3]);
3046 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3047 checkGLcall("glClipPlane");
3049 glPopMatrix();
3050 LEAVE_GL();
3052 return WINED3D_OK;
3055 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 TRACE("(%p) : for idx %ld\n", This, Index);
3059 /* Validate Index */
3060 if (Index >= GL_LIMITS(clipplanes)) {
3061 TRACE("Application has requested clipplane this device doesn't support\n");
3062 return WINED3DERR_INVALIDCALL;
3065 pPlane[0] = This->stateBlock->clipplane[Index][0];
3066 pPlane[1] = This->stateBlock->clipplane[Index][1];
3067 pPlane[2] = This->stateBlock->clipplane[Index][2];
3068 pPlane[3] = This->stateBlock->clipplane[Index][3];
3069 return WINED3D_OK;
3072 /*****
3073 * Get / Set Clip Plane Status
3074 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3075 *****/
3076 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 FIXME("(%p) : stub\n", This);
3079 if (NULL == pClipStatus) {
3080 return WINED3DERR_INVALIDCALL;
3082 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3083 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3084 return WINED3D_OK;
3087 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 FIXME("(%p) : stub\n", This);
3090 if (NULL == pClipStatus) {
3091 return WINED3DERR_INVALIDCALL;
3093 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3094 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3095 return WINED3D_OK;
3098 /*****
3099 * Get / Set Material
3100 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3101 *****/
3102 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 This->updateStateBlock->changed.material = TRUE;
3106 This->updateStateBlock->set.material = TRUE;
3107 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3109 /* Handle recording of state blocks */
3110 if (This->isRecordingState) {
3111 TRACE("Recording... not performing anything\n");
3112 return WINED3D_OK;
3115 ENTER_GL();
3116 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3117 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3118 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3119 pMaterial->Ambient.b, pMaterial->Ambient.a);
3120 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3121 pMaterial->Specular.b, pMaterial->Specular.a);
3122 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3123 pMaterial->Emissive.b, pMaterial->Emissive.a);
3124 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3126 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3127 checkGLcall("glMaterialfv(GL_AMBIENT)");
3128 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3129 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3131 /* Only change material color if specular is enabled, otherwise it is set to black */
3132 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3133 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3134 checkGLcall("glMaterialfv(GL_SPECULAR");
3135 } else {
3136 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3137 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3138 checkGLcall("glMaterialfv(GL_SPECULAR");
3140 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3141 checkGLcall("glMaterialfv(GL_EMISSION)");
3142 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3143 checkGLcall("glMaterialf(GL_SHININESS");
3145 LEAVE_GL();
3146 return WINED3D_OK;
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3152 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3153 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3154 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3155 pMaterial->Ambient.b, pMaterial->Ambient.a);
3156 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3157 pMaterial->Specular.b, pMaterial->Specular.a);
3158 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3159 pMaterial->Emissive.b, pMaterial->Emissive.a);
3160 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3162 return WINED3D_OK;
3165 /*****
3166 * Get / Set Indices
3167 *****/
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3169 UINT BaseVertexIndex) {
3170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 IWineD3DIndexBuffer *oldIdxs;
3173 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3174 oldIdxs = This->updateStateBlock->pIndexData;
3176 This->updateStateBlock->changed.indices = TRUE;
3177 This->updateStateBlock->set.indices = TRUE;
3178 This->updateStateBlock->pIndexData = pIndexData;
3179 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3181 /* Handle recording of state blocks */
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3184 return WINED3D_OK;
3187 if (NULL != pIndexData) {
3188 IWineD3DIndexBuffer_AddRef(pIndexData);
3190 if (NULL != oldIdxs) {
3191 IWineD3DIndexBuffer_Release(oldIdxs);
3193 return WINED3D_OK;
3196 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3199 *ppIndexData = This->stateBlock->pIndexData;
3201 /* up ref count on ppindexdata */
3202 if (*ppIndexData) {
3203 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3204 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3205 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3206 }else{
3207 TRACE("(%p) No index data set\n", This);
3209 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3211 return WINED3D_OK;
3214 /*****
3215 * Get / Set Viewports
3216 *****/
3217 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 TRACE("(%p)\n", This);
3221 This->updateStateBlock->changed.viewport = TRUE;
3222 This->updateStateBlock->set.viewport = TRUE;
3223 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3225 /* Handle recording of state blocks */
3226 if (This->isRecordingState) {
3227 TRACE("Recording... not performing anything\n");
3228 return WINED3D_OK;
3230 This->viewport_changed = TRUE;
3232 ENTER_GL();
3234 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3235 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3237 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3238 checkGLcall("glDepthRange");
3239 /* Note: GL requires lower left, DirectX supplies upper left */
3240 /* TODO: replace usage of renderTarget with context management */
3241 glViewport(pViewport->X,
3242 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3243 pViewport->Width, pViewport->Height);
3245 checkGLcall("glViewport");
3247 LEAVE_GL();
3249 return WINED3D_OK;
3253 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 TRACE("(%p)\n", This);
3256 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3257 return WINED3D_OK;
3260 static void renderstate_stencil_twosided(
3261 IWineD3DDeviceImpl *This,
3262 GLint face,
3263 GLint func,
3264 GLint ref,
3265 GLuint mask,
3266 GLint stencilFail,
3267 GLint depthFail,
3268 GLint stencilPass ) {
3269 #if 0 /* Don't use OpenGL 2.0 calls for now */
3270 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3271 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3272 checkGLcall("glStencilFuncSeparate(...)");
3273 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3274 checkGLcall("glStencilOpSeparate(...)");
3276 else
3277 #endif
3278 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3279 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3280 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3281 GL_EXTCALL(glActiveStencilFaceEXT(face));
3282 checkGLcall("glActiveStencilFaceEXT(...)");
3283 glStencilFunc(func, ref, mask);
3284 checkGLcall("glStencilFunc(...)");
3285 glStencilOp(stencilFail, depthFail, stencilPass);
3286 checkGLcall("glStencilOp(...)");
3287 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3288 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3289 checkGLcall("glStencilFuncSeparateATI(...)");
3290 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3291 checkGLcall("glStencilOpSeparateATI(...)");
3292 } else {
3293 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3297 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3298 DWORD onesided_enable = FALSE;
3299 DWORD twosided_enable = FALSE;
3300 GLint func = GL_ALWAYS;
3301 GLint func_ccw = GL_ALWAYS;
3302 GLint ref = 0;
3303 GLuint mask = 0;
3304 GLint stencilFail = GL_KEEP;
3305 GLint depthFail = GL_KEEP;
3306 GLint stencilPass = GL_KEEP;
3307 GLint stencilFail_ccw = GL_KEEP;
3308 GLint depthFail_ccw = GL_KEEP;
3309 GLint stencilPass_ccw = GL_KEEP;
3311 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3312 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3313 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3314 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3315 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3316 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3317 func = GL_ALWAYS;
3318 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3319 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3320 func = GL_ALWAYS;
3321 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3322 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3323 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3324 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3325 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3326 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3327 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3328 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3329 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3330 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3331 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3332 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3333 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3334 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3335 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3336 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3338 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3339 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3340 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3341 onesided_enable, twosided_enable, ref, mask,
3342 func, stencilFail, depthFail, stencilPass,
3343 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3345 if (twosided_enable) {
3346 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3347 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3348 } else {
3349 if (onesided_enable) {
3350 glEnable(GL_STENCIL_TEST);
3351 checkGLcall("glEnable GL_STENCIL_TEST");
3352 glStencilFunc(func, ref, mask);
3353 checkGLcall("glStencilFunc(...)");
3354 glStencilOp(stencilFail, depthFail, stencilPass);
3355 checkGLcall("glStencilOp(...)");
3356 } else {
3357 glDisable(GL_STENCIL_TEST);
3358 checkGLcall("glDisable GL_STENCIL_TEST");
3363 /*****
3364 * Get / Set Render States
3365 * TODO: Verify against dx9 definitions
3366 *****/
3367 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3370 DWORD OldValue = This->stateBlock->renderState[State];
3372 /* Simple way of referring to either a DWORD or a 4 byte float */
3373 union {
3374 DWORD d;
3375 float f;
3376 } tmpvalue;
3378 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3379 This->updateStateBlock->changed.renderState[State] = TRUE;
3380 This->updateStateBlock->set.renderState[State] = TRUE;
3381 This->updateStateBlock->renderState[State] = Value;
3383 /* Handle recording of state blocks */
3384 if (This->isRecordingState) {
3385 TRACE("Recording... not performing anything\n");
3386 return WINED3D_OK;
3389 ENTER_GL();
3391 switch (State) {
3392 case WINED3DRS_FILLMODE :
3393 switch ((D3DFILLMODE) Value) {
3394 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3395 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3396 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3397 default:
3398 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3400 checkGLcall("glPolygonMode (fillmode)");
3401 break;
3403 case WINED3DRS_LIGHTING :
3404 if (Value) {
3405 glEnable(GL_LIGHTING);
3406 checkGLcall("glEnable GL_LIGHTING");
3407 } else {
3408 glDisable(GL_LIGHTING);
3409 checkGLcall("glDisable GL_LIGHTING");
3411 break;
3413 case WINED3DRS_ZENABLE :
3414 switch ((D3DZBUFFERTYPE) Value) {
3415 case D3DZB_FALSE:
3416 glDisable(GL_DEPTH_TEST);
3417 checkGLcall("glDisable GL_DEPTH_TEST");
3418 break;
3419 case D3DZB_TRUE:
3420 glEnable(GL_DEPTH_TEST);
3421 checkGLcall("glEnable GL_DEPTH_TEST");
3422 break;
3423 case D3DZB_USEW:
3424 glEnable(GL_DEPTH_TEST);
3425 checkGLcall("glEnable GL_DEPTH_TEST");
3426 FIXME("W buffer is not well handled\n");
3427 break;
3428 default:
3429 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3431 break;
3433 case WINED3DRS_CULLMODE :
3435 /* If we are culling "back faces with clockwise vertices" then
3436 set front faces to be counter clockwise and enable culling
3437 of back faces */
3438 switch ((D3DCULL) Value) {
3439 case D3DCULL_NONE:
3440 glDisable(GL_CULL_FACE);
3441 checkGLcall("glDisable GL_CULL_FACE");
3442 break;
3443 case D3DCULL_CW:
3444 glEnable(GL_CULL_FACE);
3445 checkGLcall("glEnable GL_CULL_FACE");
3446 if (This->renderUpsideDown) {
3447 glFrontFace(GL_CW);
3448 checkGLcall("glFrontFace GL_CW");
3449 } else {
3450 glFrontFace(GL_CCW);
3451 checkGLcall("glFrontFace GL_CCW");
3453 glCullFace(GL_BACK);
3454 break;
3455 case D3DCULL_CCW:
3456 glEnable(GL_CULL_FACE);
3457 checkGLcall("glEnable GL_CULL_FACE");
3458 if (This->renderUpsideDown) {
3459 glFrontFace(GL_CCW);
3460 checkGLcall("glFrontFace GL_CCW");
3461 } else {
3462 glFrontFace(GL_CW);
3463 checkGLcall("glFrontFace GL_CW");
3465 glCullFace(GL_BACK);
3466 break;
3467 default:
3468 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3470 break;
3472 case WINED3DRS_SHADEMODE :
3473 switch ((D3DSHADEMODE) Value) {
3474 case D3DSHADE_FLAT:
3475 glShadeModel(GL_FLAT);
3476 checkGLcall("glShadeModel");
3477 break;
3478 case D3DSHADE_GOURAUD:
3479 glShadeModel(GL_SMOOTH);
3480 checkGLcall("glShadeModel");
3481 break;
3482 case D3DSHADE_PHONG:
3483 FIXME("D3DSHADE_PHONG isn't supported\n");
3484 break;
3485 default:
3486 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3488 break;
3490 case WINED3DRS_DITHERENABLE :
3491 if (Value) {
3492 glEnable(GL_DITHER);
3493 checkGLcall("glEnable GL_DITHER");
3494 } else {
3495 glDisable(GL_DITHER);
3496 checkGLcall("glDisable GL_DITHER");
3498 break;
3500 case WINED3DRS_ZWRITEENABLE :
3501 if (Value) {
3502 glDepthMask(1);
3503 checkGLcall("glDepthMask");
3504 } else {
3505 glDepthMask(0);
3506 checkGLcall("glDepthMask");
3508 break;
3510 case WINED3DRS_ZFUNC :
3512 int glParm = CompareFunc(Value);
3514 if(glParm) {
3515 glDepthFunc(glParm);
3516 checkGLcall("glDepthFunc");
3519 break;
3521 case WINED3DRS_AMBIENT :
3523 float col[4];
3524 D3DCOLORTOGLFLOAT4(Value, col);
3525 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3526 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3527 checkGLcall("glLightModel for MODEL_AMBIENT");
3530 break;
3532 case WINED3DRS_ALPHABLENDENABLE :
3533 if (Value) {
3534 glEnable(GL_BLEND);
3535 checkGLcall("glEnable GL_BLEND");
3536 } else {
3537 glDisable(GL_BLEND);
3538 checkGLcall("glDisable GL_BLEND");
3540 break;
3542 case WINED3DRS_SRCBLEND :
3543 case WINED3DRS_DESTBLEND :
3545 int newVal = GL_ZERO;
3546 switch (Value) {
3547 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3548 case D3DBLEND_ONE : newVal = GL_ONE; break;
3549 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3550 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3551 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3552 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3553 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3554 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3555 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3556 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3557 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3559 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3560 This->srcBlend = newVal;
3561 This->dstBlend = newVal;
3562 break;
3564 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3565 This->srcBlend = newVal;
3566 This->dstBlend = newVal;
3567 break;
3568 case D3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3569 case D3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3570 default:
3571 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3574 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3575 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3576 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3577 glBlendFunc(This->srcBlend, This->dstBlend);
3579 checkGLcall("glBlendFunc");
3581 break;
3583 case WINED3DRS_ALPHATESTENABLE :
3584 case WINED3DRS_ALPHAFUNC :
3585 case WINED3DRS_ALPHAREF :
3586 case WINED3DRS_COLORKEYENABLE :
3588 int glParm = 0;
3589 float ref;
3590 BOOL enable_ckey = FALSE;
3592 IWineD3DSurfaceImpl *surf;
3594 /* Find out if the texture on the first stage has a ckey set */
3595 if(This->stateBlock->textures[0]) {
3596 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3597 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3600 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3601 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3602 glEnable(GL_ALPHA_TEST);
3603 checkGLcall("glEnable GL_ALPHA_TEST");
3604 } else {
3605 glDisable(GL_ALPHA_TEST);
3606 checkGLcall("glDisable GL_ALPHA_TEST");
3607 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3608 * enable call
3610 break;
3613 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3614 glParm = GL_NOTEQUAL;
3615 ref = 0.0;
3616 } else {
3617 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3618 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3620 if(glParm) {
3621 This->alphafunc = glParm;
3622 glAlphaFunc(glParm, ref);
3623 checkGLcall("glAlphaFunc");
3626 break;
3628 case WINED3DRS_CLIPPLANEENABLE :
3629 case WINED3DRS_CLIPPING :
3631 /* Ensure we only do the changed clip planes */
3632 DWORD enable = 0xFFFFFFFF;
3633 DWORD disable = 0x00000000;
3635 /* If enabling / disabling all */
3636 if (State == WINED3DRS_CLIPPING) {
3637 if (Value) {
3638 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3639 disable = 0x00;
3640 } else {
3641 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3642 enable = 0x00;
3644 } else {
3645 enable = Value & ~OldValue;
3646 disable = ~Value & OldValue;
3649 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3650 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3651 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3652 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3653 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3654 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3656 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3657 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3658 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3659 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3660 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3661 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3663 /** update clipping status */
3664 if (enable) {
3665 This->stateBlock->clip_status.ClipUnion = 0;
3666 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3667 } else {
3668 This->stateBlock->clip_status.ClipUnion = 0;
3669 This->stateBlock->clip_status.ClipIntersection = 0;
3672 break;
3674 case WINED3DRS_BLENDOP :
3676 int glParm = GL_FUNC_ADD;
3678 switch ((D3DBLENDOP) Value) {
3679 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3680 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3681 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3682 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3683 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3684 default:
3685 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3688 if(GL_SUPPORT(ARB_IMAGING)) {
3689 TRACE("glBlendEquation(%x)\n", glParm);
3690 GL_EXTCALL(glBlendEquation(glParm));
3691 checkGLcall("glBlendEquation");
3692 } else {
3693 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3696 break;
3698 case WINED3DRS_TEXTUREFACTOR :
3700 unsigned int i;
3702 /* Note the texture color applies to all textures whereas
3703 GL_TEXTURE_ENV_COLOR applies to active only */
3704 float col[4];
3705 D3DCOLORTOGLFLOAT4(Value, col);
3707 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3708 /* And now the default texture color as well */
3709 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3710 /* Note the D3DRS value applies to all textures, but GL has one
3711 per texture, so apply it now ready to be used! */
3712 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3713 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3714 checkGLcall("glActiveTextureARB");
3715 } else if (i>0) {
3716 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3719 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3720 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3724 break;
3726 case WINED3DRS_SPECULARENABLE :
3728 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3729 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3730 specular color. This is wrong:
3731 Separate specular color means the specular colour is maintained separately, whereas
3732 single color means it is merged in. However in both cases they are being used to
3733 some extent.
3734 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3735 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3736 running 1.4 yet!
3739 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3740 * Instead, we need to setup the FinalCombiner properly.
3742 * The default setup for the FinalCombiner is:
3744 * <variable> <input> <mapping> <usage>
3745 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3746 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3747 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3748 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3749 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3750 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3751 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3753 * That's pretty much fine as it is, except for variable B, which needs to take
3754 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3755 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3758 if (Value) {
3759 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3760 checkGLcall("glMaterialfv");
3761 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3762 glEnable(GL_COLOR_SUM_EXT);
3763 } else {
3764 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3766 checkGLcall("glEnable(GL_COLOR_SUM)");
3768 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3769 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3770 checkGLcall("glFinalCombinerInputNV()");
3772 } else {
3773 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3775 /* for the case of enabled lighting: */
3776 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3777 checkGLcall("glMaterialfv");
3779 /* for the case of disabled lighting: */
3780 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3781 glDisable(GL_COLOR_SUM_EXT);
3782 } else {
3783 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3785 checkGLcall("glDisable(GL_COLOR_SUM)");
3787 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3788 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3789 checkGLcall("glFinalCombinerInputNV()");
3793 break;
3795 case WINED3DRS_STENCILENABLE :
3796 case WINED3DRS_TWOSIDEDSTENCILMODE :
3797 case WINED3DRS_STENCILFUNC :
3798 case WINED3DRS_CCW_STENCILFUNC :
3799 case WINED3DRS_STENCILREF :
3800 case WINED3DRS_STENCILMASK :
3801 case WINED3DRS_STENCILFAIL :
3802 case WINED3DRS_STENCILZFAIL :
3803 case WINED3DRS_STENCILPASS :
3804 case WINED3DRS_CCW_STENCILFAIL :
3805 case WINED3DRS_CCW_STENCILZFAIL :
3806 case WINED3DRS_CCW_STENCILPASS :
3807 renderstate_stencil(This, State, Value);
3808 break;
3809 case WINED3DRS_STENCILWRITEMASK :
3811 glStencilMask(Value);
3812 TRACE("glStencilMask(%lu)\n", Value);
3813 checkGLcall("glStencilMask");
3815 break;
3817 case WINED3DRS_FOGENABLE :
3819 if (Value) {
3820 glEnable(GL_FOG);
3821 checkGLcall("glEnable GL_FOG");
3822 } else {
3823 glDisable(GL_FOG);
3824 checkGLcall("glDisable GL_FOG");
3827 break;
3829 case WINED3DRS_RANGEFOGENABLE :
3831 if (Value) {
3832 TRACE("Enabled RANGEFOG\n");
3833 } else {
3834 TRACE("Disabled RANGEFOG\n");
3837 break;
3839 case WINED3DRS_FOGCOLOR :
3841 float col[4];
3842 D3DCOLORTOGLFLOAT4(Value, col);
3843 /* Set the default alpha blend color */
3844 glFogfv(GL_FOG_COLOR, &col[0]);
3845 checkGLcall("glFog GL_FOG_COLOR");
3847 break;
3849 case WINED3DRS_FOGTABLEMODE :
3850 case WINED3DRS_FOGVERTEXMODE :
3852 /* 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." */
3853 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3854 glHint(GL_FOG_HINT, GL_FASTEST);
3855 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3856 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3857 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3858 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3860 case D3DFOG_EXP: {
3861 if(!This->last_was_rhw) {
3862 glFogi(GL_FOG_MODE, GL_EXP);
3863 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3864 if(GL_SUPPORT(EXT_FOG_COORD)) {
3865 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3866 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3867 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3868 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3870 break;
3873 case D3DFOG_EXP2: {
3874 if(!This->last_was_rhw) {
3875 glFogi(GL_FOG_MODE, GL_EXP2);
3876 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3877 if(GL_SUPPORT(EXT_FOG_COORD)) {
3878 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3879 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3880 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3881 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3883 break;
3886 case D3DFOG_LINEAR: {
3887 if(!This->last_was_rhw) {
3888 glFogi(GL_FOG_MODE, GL_LINEAR);
3889 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3890 if(GL_SUPPORT(EXT_FOG_COORD)) {
3891 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3892 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3893 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3894 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3896 break;
3899 case D3DFOG_NONE: {
3900 /* Both are none? According to msdn the alpha channel of the specular
3901 * color contains a fog factor. Set it in drawStridedSlow.
3902 * Same happens with Vertexfog on transformed vertices
3904 if(GL_SUPPORT(EXT_FOG_COORD)) {
3905 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3906 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3907 glFogi(GL_FOG_MODE, GL_LINEAR);
3908 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3909 glFogf(GL_FOG_START, (float) 0xff);
3910 checkGLcall("glFogfv GL_FOG_START");
3911 glFogf(GL_FOG_END, 0.0);
3912 checkGLcall("glFogfv GL_FOG_END");
3913 } else {
3914 /* Disable GL fog, handle this in software in drawStridedSlow */
3915 glDisable(GL_FOG);
3916 checkGLcall("glDisable(GL_FOG)");
3918 break;
3920 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3922 } else {
3923 glHint(GL_FOG_HINT, GL_NICEST);
3924 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3925 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3926 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3927 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3928 if(GL_SUPPORT(EXT_FOG_COORD)) {
3929 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3930 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3931 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3932 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3934 break;
3935 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3936 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3937 if(GL_SUPPORT(EXT_FOG_COORD)) {
3938 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3939 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3940 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3941 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3943 break;
3944 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3945 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3946 if(GL_SUPPORT(EXT_FOG_COORD)) {
3947 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3948 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3949 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3950 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3952 break;
3953 case D3DFOG_NONE: /* Won't happen */
3954 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3957 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3958 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3961 break;
3963 case WINED3DRS_FOGSTART :
3965 tmpvalue.d = Value;
3966 glFogfv(GL_FOG_START, &tmpvalue.f);
3967 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
3968 TRACE("Fog Start == %f\n", tmpvalue.f);
3970 break;
3972 case WINED3DRS_FOGEND :
3974 tmpvalue.d = Value;
3975 glFogfv(GL_FOG_END, &tmpvalue.f);
3976 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
3977 TRACE("Fog End == %f\n", tmpvalue.f);
3979 break;
3981 case WINED3DRS_FOGDENSITY :
3983 tmpvalue.d = Value;
3984 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
3985 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
3987 break;
3989 case WINED3DRS_VERTEXBLEND :
3991 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
3992 TRACE("Vertex Blending state to %ld\n", Value);
3994 break;
3996 case WINED3DRS_TWEENFACTOR :
3998 tmpvalue.d = Value;
3999 This->updateStateBlock->tween_factor = tmpvalue.f;
4000 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4002 break;
4004 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4006 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4008 break;
4010 case WINED3DRS_COLORVERTEX :
4011 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4012 case WINED3DRS_SPECULARMATERIALSOURCE :
4013 case WINED3DRS_AMBIENTMATERIALSOURCE :
4014 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4016 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4018 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4019 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4020 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4021 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4022 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4023 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4025 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4026 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4027 Parm = GL_AMBIENT_AND_DIFFUSE;
4028 } else {
4029 Parm = GL_DIFFUSE;
4031 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4032 Parm = GL_AMBIENT;
4033 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4034 Parm = GL_EMISSION;
4035 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4036 Parm = GL_SPECULAR;
4037 } else {
4038 Parm = -1;
4041 if (Parm == -1) {
4042 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4043 } else {
4044 This->tracking_color = NEEDS_TRACKING;
4045 This->tracking_parm = Parm;
4048 } else {
4049 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4052 break;
4054 case WINED3DRS_LINEPATTERN :
4056 union {
4057 DWORD d;
4058 D3DLINEPATTERN lp;
4059 } tmppattern;
4060 tmppattern.d = Value;
4062 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4064 if (tmppattern.lp.wRepeatFactor) {
4065 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4066 checkGLcall("glLineStipple(repeat, linepattern)");
4067 glEnable(GL_LINE_STIPPLE);
4068 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4069 } else {
4070 glDisable(GL_LINE_STIPPLE);
4071 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4074 break;
4076 case WINED3DRS_ZBIAS : /* D3D8 only */
4078 if (Value) {
4079 tmpvalue.d = Value;
4080 TRACE("ZBias value %f\n", tmpvalue.f);
4081 glPolygonOffset(0, -tmpvalue.f);
4082 checkGLcall("glPolygonOffset(0, -Value)");
4083 glEnable(GL_POLYGON_OFFSET_FILL);
4084 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4085 glEnable(GL_POLYGON_OFFSET_LINE);
4086 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4087 glEnable(GL_POLYGON_OFFSET_POINT);
4088 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4089 } else {
4090 glDisable(GL_POLYGON_OFFSET_FILL);
4091 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4092 glDisable(GL_POLYGON_OFFSET_LINE);
4093 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4094 glDisable(GL_POLYGON_OFFSET_POINT);
4095 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4098 break;
4100 case WINED3DRS_NORMALIZENORMALS :
4101 if (Value) {
4102 glEnable(GL_NORMALIZE);
4103 checkGLcall("glEnable(GL_NORMALIZE);");
4104 } else {
4105 glDisable(GL_NORMALIZE);
4106 checkGLcall("glDisable(GL_NORMALIZE);");
4108 break;
4110 case WINED3DRS_POINTSIZE :
4111 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4112 tmpvalue.d = Value;
4113 TRACE("Set point size to %f\n", tmpvalue.f);
4114 glPointSize(tmpvalue.f);
4115 checkGLcall("glPointSize(...);");
4116 break;
4118 case WINED3DRS_POINTSIZE_MIN :
4119 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4120 tmpvalue.d = Value;
4121 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4122 checkGLcall("glPointParameterfEXT(...);");
4123 } else {
4124 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4126 break;
4128 case WINED3DRS_POINTSIZE_MAX :
4129 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4130 tmpvalue.d = Value;
4131 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4132 checkGLcall("glPointParameterfEXT(...);");
4133 } else {
4134 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4136 break;
4138 case WINED3DRS_POINTSCALE_A :
4139 case WINED3DRS_POINTSCALE_B :
4140 case WINED3DRS_POINTSCALE_C :
4141 case WINED3DRS_POINTSCALEENABLE :
4144 * POINTSCALEENABLE controls how point size value is treated. If set to
4145 * true, the point size is scaled with respect to height of viewport.
4146 * When set to false point size is in pixels.
4148 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4151 /* Default values */
4152 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4155 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4156 * This means that OpenGL will clamp really small point sizes to 1.0f.
4157 * To correct for this we need to multiply by the scale factor when sizes
4158 * are less than 1.0f. scale_factor = 1.0f / point_size.
4160 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4161 if(pointSize > 0.0f) {
4162 GLfloat scaleFactor;
4164 if(pointSize < 1.0f) {
4165 scaleFactor = pointSize * pointSize;
4166 } else {
4167 scaleFactor = 1.0f;
4170 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4171 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4172 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4173 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4174 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4175 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4176 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4180 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4181 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4182 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4184 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4185 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4186 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4187 } else {
4188 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4190 break;
4192 case WINED3DRS_COLORWRITEENABLE :
4194 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4195 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4196 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4197 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4198 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4199 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4200 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4201 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4202 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4203 checkGLcall("glColorMask(...)");
4205 break;
4207 case WINED3DRS_LOCALVIEWER :
4209 GLint state = (Value) ? 1 : 0;
4210 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4211 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4213 break;
4215 case WINED3DRS_LASTPIXEL :
4217 if (Value) {
4218 TRACE("Last Pixel Drawing Enabled\n");
4219 } else {
4220 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4223 break;
4225 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4227 if (Value) {
4228 TRACE("Software Processing Enabled\n");
4229 } else {
4230 TRACE("Software Processing Disabled\n");
4233 break;
4235 /** not supported */
4236 case WINED3DRS_ZVISIBLE :
4238 LEAVE_GL();
4239 return WINED3DERR_INVALIDCALL;
4241 case WINED3DRS_POINTSPRITEENABLE :
4243 /* TODO: NV_POINT_SPRITE */
4244 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4245 TRACE("Point sprites not supported\n");
4246 break;
4250 * Point sprites are always enabled. Value controls texture coordinate
4251 * replacement mode. Must be set true for point sprites to use
4252 * textures.
4254 glEnable(GL_POINT_SPRITE_ARB);
4255 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4257 if (Value) {
4258 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4259 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4260 } else {
4261 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4262 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4264 break;
4266 case WINED3DRS_EDGEANTIALIAS :
4268 if(Value) {
4269 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4270 glEnable(GL_BLEND);
4271 checkGLcall("glEnable(GL_BLEND)");
4272 glEnable(GL_LINE_SMOOTH);
4273 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4274 } else {
4275 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4276 glDisable(GL_BLEND);
4277 checkGLcall("glDisable(GL_BLEND)");
4279 glDisable(GL_LINE_SMOOTH);
4280 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4282 break;
4284 case WINED3DRS_WRAP0 :
4285 case WINED3DRS_WRAP1 :
4286 case WINED3DRS_WRAP2 :
4287 case WINED3DRS_WRAP3 :
4288 case WINED3DRS_WRAP4 :
4289 case WINED3DRS_WRAP5 :
4290 case WINED3DRS_WRAP6 :
4291 case WINED3DRS_WRAP7 :
4292 case WINED3DRS_WRAP8 :
4293 case WINED3DRS_WRAP9 :
4294 case WINED3DRS_WRAP10 :
4295 case WINED3DRS_WRAP11 :
4296 case WINED3DRS_WRAP12 :
4297 case WINED3DRS_WRAP13 :
4298 case WINED3DRS_WRAP14 :
4299 case WINED3DRS_WRAP15 :
4301 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4302 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4303 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4304 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4305 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4307 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4310 if(Value) {
4311 ERR("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4313 break;
4316 case WINED3DRS_MULTISAMPLEANTIALIAS :
4318 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4319 if(Value) {
4320 glEnable(GL_MULTISAMPLE_ARB);
4321 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4322 } else {
4323 glDisable(GL_MULTISAMPLE_ARB);
4324 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4326 } else {
4327 if(Value) {
4328 ERR("Multisample antialiasing not supported by gl\n");
4331 break;
4334 case WINED3DRS_SCISSORTESTENABLE :
4336 if(Value) {
4337 glEnable(GL_SCISSOR_TEST);
4338 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4339 } else {
4340 glDisable(GL_SCISSOR_TEST);
4341 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4343 break;
4345 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4347 if(Value) {
4348 tmpvalue.d = Value;
4349 glEnable(GL_POLYGON_OFFSET_FILL);
4350 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4351 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4352 checkGLcall("glPolygonOffset(...)");
4353 } else {
4354 glDisable(GL_POLYGON_OFFSET_FILL);
4355 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4357 break;
4359 case WINED3DRS_ANTIALIASEDLINEENABLE :
4361 if(Value) {
4362 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4363 glEnable(GL_BLEND);
4364 checkGLcall("glEnable(GL_BLEND)");
4365 glEnable(GL_LINE_SMOOTH);
4366 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4367 } else {
4368 glDisable(GL_BLEND);
4369 checkGLcall("glDisable(GL_BLEND)");
4370 glDisable(GL_LINE_SMOOTH);
4371 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4373 break;
4375 case WINED3DRS_DEPTHBIAS :
4377 if(Value) {
4378 tmpvalue.d = Value;
4379 glEnable(GL_POLYGON_OFFSET_FILL);
4380 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4381 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4382 checkGLcall("glPolygonOffset(...)");
4383 } else {
4384 glDisable(GL_POLYGON_OFFSET_FILL);
4385 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4387 break;
4390 case WINED3DRS_TEXTUREPERSPECTIVE :
4392 if (Value)
4393 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4394 else
4395 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4396 break;
4399 case WINED3DRS_STIPPLEDALPHA :
4401 if (Value)
4402 ERR(" Stippled Alpha not supported yet.\n");
4403 break;
4405 case WINED3DRS_ANTIALIAS :
4407 if (Value)
4408 ERR(" Antialias not supported yet.\n");
4409 break;
4412 case WINED3DRS_MULTISAMPLEMASK :
4414 if(0xFFFFFFFF != Value)
4415 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4416 break;
4419 case WINED3DRS_PATCHEDGESTYLE :
4421 if(D3DPATCHEDGE_DISCRETE != Value)
4422 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4423 break;
4426 case WINED3DRS_PATCHSEGMENTS :
4428 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4429 tmpvalue.f = 1.0f;
4430 if(tmpvalue.d != Value)
4431 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4432 break;
4435 case WINED3DRS_DEBUGMONITORTOKEN :
4437 /* Only useful for "debug builds". */
4438 if(0xbaadcafe != Value) {
4439 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4440 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4441 * but our tests disagree.
4442 * We do not claim to implement a debugging lib, so do not write an ERR
4444 WARN("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4446 break;
4449 case WINED3DRS_POSITIONDEGREE :
4451 if(D3DDEGREE_CUBIC != Value)
4452 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4453 break;
4456 case WINED3DRS_NORMALDEGREE :
4458 if(D3DDEGREE_LINEAR != Value)
4459 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4460 break;
4463 case WINED3DRS_MINTESSELLATIONLEVEL :
4464 case WINED3DRS_MAXTESSELLATIONLEVEL :
4465 case WINED3DRS_ADAPTIVETESS_X :
4466 case WINED3DRS_ADAPTIVETESS_Y :
4467 case WINED3DRS_ADAPTIVETESS_Z :
4468 case WINED3DRS_ADAPTIVETESS_W :
4470 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4471 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4472 else
4473 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4474 break;
4477 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4479 if(Value)
4480 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4481 break;
4484 case WINED3DRS_COLORWRITEENABLE1 :
4485 case WINED3DRS_COLORWRITEENABLE2 :
4486 case WINED3DRS_COLORWRITEENABLE3 :
4488 /* depends on WINED3DRS_COLORWRITEENABLE. */
4489 if(0x0000000F != Value)
4490 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4491 break;
4494 case WINED3DRS_BLENDFACTOR :
4496 float col[4];
4497 if (GL_SUPPORT(ARB_IMAGING)) {
4499 TRACE("Setting BlendFactor to %ld", Value);
4501 D3DCOLORTOGLFLOAT4(Value, col);
4502 if (0xFFFFFFFF != Value) {
4503 glEnable(GL_BLEND);
4504 checkGLcall("glEnable(GL_BLEND)");
4506 else {
4507 glDisable(GL_BLEND);
4508 checkGLcall("glDisable(GL_BLEND)");
4510 glBlendColor (col[0],col[1],col[2],col[3]);
4511 } else {
4512 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
4514 break;
4517 case WINED3DRS_SRGBWRITEENABLE :
4519 if(Value)
4520 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4521 break;
4524 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4526 if(Value)
4527 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4528 break;
4531 case WINED3DRS_SRCBLENDALPHA :
4532 case WINED3DRS_DESTBLENDALPHA :
4533 case WINED3DRS_BLENDOPALPHA :
4535 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4536 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4537 else
4538 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4539 break;
4542 default:
4543 FIXME("(%p)->(%s,%ld) unknown state\n", This, debug_d3drenderstate(State), Value);
4546 LEAVE_GL();
4548 return WINED3D_OK;
4551 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4553 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4554 *pValue = This->stateBlock->renderState[State];
4555 return WINED3D_OK;
4558 /*****
4559 * Get / Set Sampler States
4560 * TODO: Verify against dx9 definitions
4561 *****/
4563 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 * SetSampler is designed to allow for more than the standard up to 8 textures
4567 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4568 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4570 * http://developer.nvidia.com/object/General_FAQ.html#t6
4572 * There are two new settings for GForce
4573 * the sampler one:
4574 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4575 * and the texture one:
4576 * GL_MAX_TEXTURE_COORDS_ARB.
4577 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4578 ******************/
4579 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4580 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4581 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4582 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4583 return WINED3DERR_INVALIDCALL;
4586 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4587 debug_d3dsamplerstate(Type), Type, Value);
4588 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4589 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4590 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4592 /* Handle recording of state blocks */
4593 if (This->isRecordingState) {
4594 TRACE("Recording... not performing anything\n");
4595 return WINED3D_OK;
4598 return WINED3D_OK;
4601 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 /** TODO: check that sampler is in range **/
4604 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4605 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4607 return WINED3D_OK;
4610 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612 ENTER_GL();
4614 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4615 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4616 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4617 LEAVE_GL();
4619 return WINED3D_OK;
4622 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 GLint scissorBox[4];
4626 ENTER_GL();
4627 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4628 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4629 pRect->left = scissorBox[0];
4630 pRect->top = scissorBox[1];
4631 pRect->right = scissorBox[0] + scissorBox[2];
4632 pRect->bottom = scissorBox[1] + scissorBox[3];
4633 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4634 LEAVE_GL();
4635 return WINED3D_OK;
4638 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4640 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4642 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4644 This->updateStateBlock->vertexDecl = pDecl;
4645 This->updateStateBlock->changed.vertexDecl = TRUE;
4646 This->updateStateBlock->set.vertexDecl = TRUE;
4648 if (This->isRecordingState) {
4649 TRACE("Recording... not performing anything\n");
4652 if (NULL != pDecl) {
4653 IWineD3DVertexDeclaration_AddRef(pDecl);
4655 if (NULL != oldDecl) {
4656 IWineD3DVertexDeclaration_Release(oldDecl);
4658 return WINED3D_OK;
4661 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4666 *ppDecl = This->stateBlock->vertexDecl;
4667 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4668 return WINED3D_OK;
4671 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4675 This->updateStateBlock->vertexShader = pShader;
4676 This->updateStateBlock->changed.vertexShader = TRUE;
4677 This->updateStateBlock->set.vertexShader = TRUE;
4679 if (This->isRecordingState) {
4680 TRACE("Recording... not performing anything\n");
4683 if (NULL != pShader) {
4684 IWineD3DVertexShader_AddRef(pShader);
4686 if (NULL != oldShader) {
4687 IWineD3DVertexShader_Release(oldShader);
4690 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4692 * TODO: merge HAL shaders context switching from prototype
4694 return WINED3D_OK;
4697 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4700 if (NULL == ppShader) {
4701 return WINED3DERR_INVALIDCALL;
4703 *ppShader = This->stateBlock->vertexShader;
4704 if( NULL != *ppShader)
4705 IWineD3DVertexShader_AddRef(*ppShader);
4707 TRACE("(%p) : returning %p\n", This, *ppShader);
4708 return WINED3D_OK;
4711 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4712 IWineD3DDevice *iface,
4713 UINT start,
4714 CONST BOOL *srcData,
4715 UINT count) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 int i, cnt = min(count, MAX_CONST_B - start);
4720 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4721 iface, srcData, start, count);
4723 if (srcData == NULL || cnt < 0)
4724 return WINED3DERR_INVALIDCALL;
4726 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4727 for (i = 0; i < cnt; i++)
4728 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4730 for (i = start; i < cnt + start; ++i) {
4731 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4732 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4735 return WINED3D_OK;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4739 IWineD3DDevice *iface,
4740 UINT start,
4741 BOOL *dstData,
4742 UINT count) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 int cnt = min(count, MAX_CONST_B - start);
4747 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4748 iface, dstData, start, count);
4750 if (dstData == NULL || cnt < 0)
4751 return WINED3DERR_INVALIDCALL;
4753 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4754 return WINED3D_OK;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4758 IWineD3DDevice *iface,
4759 UINT start,
4760 CONST int *srcData,
4761 UINT count) {
4763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 int i, cnt = min(count, MAX_CONST_I - start);
4766 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4767 iface, srcData, start, count);
4769 if (srcData == NULL || cnt < 0)
4770 return WINED3DERR_INVALIDCALL;
4772 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4773 for (i = 0; i < cnt; i++)
4774 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4775 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4777 for (i = start; i < cnt + start; ++i) {
4778 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4779 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4782 return WINED3D_OK;
4785 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4786 IWineD3DDevice *iface,
4787 UINT start,
4788 int *dstData,
4789 UINT count) {
4791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4792 int cnt = min(count, MAX_CONST_I - start);
4794 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4795 iface, dstData, start, count);
4797 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4798 return WINED3DERR_INVALIDCALL;
4800 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4805 IWineD3DDevice *iface,
4806 UINT start,
4807 CONST float *srcData,
4808 UINT count) {
4810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4811 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4813 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4814 iface, srcData, start, count);
4816 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4817 return WINED3DERR_INVALIDCALL;
4819 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4820 for (i = 0; i < cnt; i++)
4821 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4822 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4824 for (i = start; i < cnt + start; ++i) {
4825 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4826 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4827 ptr->idx = i;
4828 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4829 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4831 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4834 return WINED3D_OK;
4837 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4838 IWineD3DDevice *iface,
4839 UINT start,
4840 float *dstData,
4841 UINT count) {
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4844 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4846 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4847 iface, dstData, start, count);
4849 if (dstData == NULL || cnt < 0)
4850 return WINED3DERR_INVALIDCALL;
4852 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4853 return WINED3D_OK;
4856 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4858 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4859 This->updateStateBlock->pixelShader = pShader;
4860 This->updateStateBlock->changed.pixelShader = TRUE;
4861 This->updateStateBlock->set.pixelShader = TRUE;
4863 /* Handle recording of state blocks */
4864 if (This->isRecordingState) {
4865 TRACE("Recording... not performing anything\n");
4868 if (NULL != pShader) {
4869 IWineD3DPixelShader_AddRef(pShader);
4871 if (NULL != oldShader) {
4872 IWineD3DPixelShader_Release(oldShader);
4875 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4877 * TODO: merge HAL shaders context switching from prototype
4879 return WINED3D_OK;
4882 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4885 if (NULL == ppShader) {
4886 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4887 return WINED3DERR_INVALIDCALL;
4890 *ppShader = This->stateBlock->pixelShader;
4891 if (NULL != *ppShader) {
4892 IWineD3DPixelShader_AddRef(*ppShader);
4894 TRACE("(%p) : returning %p\n", This, *ppShader);
4895 return WINED3D_OK;
4898 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4899 IWineD3DDevice *iface,
4900 UINT start,
4901 CONST BOOL *srcData,
4902 UINT count) {
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4905 int i, cnt = min(count, MAX_CONST_B - start);
4907 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4908 iface, srcData, start, count);
4910 if (srcData == NULL || cnt < 0)
4911 return WINED3DERR_INVALIDCALL;
4913 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4914 for (i = 0; i < cnt; i++)
4915 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4917 for (i = start; i < cnt + start; ++i) {
4918 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4919 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4922 return WINED3D_OK;
4925 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4926 IWineD3DDevice *iface,
4927 UINT start,
4928 BOOL *dstData,
4929 UINT count) {
4931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4932 int cnt = min(count, MAX_CONST_B - start);
4934 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4935 iface, dstData, start, count);
4937 if (dstData == NULL || cnt < 0)
4938 return WINED3DERR_INVALIDCALL;
4940 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4941 return WINED3D_OK;
4944 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4945 IWineD3DDevice *iface,
4946 UINT start,
4947 CONST int *srcData,
4948 UINT count) {
4950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4951 int i, cnt = min(count, MAX_CONST_I - start);
4953 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4954 iface, srcData, start, count);
4956 if (srcData == NULL || cnt < 0)
4957 return WINED3DERR_INVALIDCALL;
4959 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4960 for (i = 0; i < cnt; i++)
4961 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4962 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4964 for (i = start; i < cnt + start; ++i) {
4965 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4966 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4969 return WINED3D_OK;
4972 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4973 IWineD3DDevice *iface,
4974 UINT start,
4975 int *dstData,
4976 UINT count) {
4978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4979 int cnt = min(count, MAX_CONST_I - start);
4981 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4982 iface, dstData, start, count);
4984 if (dstData == NULL || cnt < 0)
4985 return WINED3DERR_INVALIDCALL;
4987 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4988 return WINED3D_OK;
4991 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4992 IWineD3DDevice *iface,
4993 UINT start,
4994 CONST float *srcData,
4995 UINT count) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5000 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5001 iface, srcData, start, count);
5003 if (srcData == NULL || cnt < 0)
5004 return WINED3DERR_INVALIDCALL;
5006 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5007 for (i = 0; i < cnt; i++)
5008 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5009 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5011 for (i = start; i < cnt + start; ++i) {
5012 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5013 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5014 ptr->idx = i;
5015 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5016 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5018 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5021 return WINED3D_OK;
5024 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5025 IWineD3DDevice *iface,
5026 UINT start,
5027 float *dstData,
5028 UINT count) {
5030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5031 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5033 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5034 iface, dstData, start, count);
5036 if (dstData == NULL || cnt < 0)
5037 return WINED3DERR_INVALIDCALL;
5039 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5040 return WINED3D_OK;
5043 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5044 static HRESULT
5045 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5046 char *dest_ptr, *dest_conv = NULL;
5047 unsigned int i;
5048 DWORD DestFVF = dest->fvf;
5049 D3DVIEWPORT9 vp;
5050 D3DMATRIX mat, proj_mat, view_mat, world_mat;
5051 BOOL doClip;
5052 int numTextures;
5054 if (SrcFVF & D3DFVF_NORMAL) {
5055 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5058 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5059 ERR("Source has no position mask\n");
5060 return WINED3DERR_INVALIDCALL;
5063 /* We might access VBOs from this code, so hold the lock */
5064 ENTER_GL();
5066 if (dest->resource.allocatedMemory == NULL) {
5067 /* This may happen if we do direct locking into a vbo. Unlikely,
5068 * but theoretically possible(ddraw processvertices test)
5070 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5071 if(!dest->resource.allocatedMemory) {
5072 LEAVE_GL();
5073 ERR("Out of memory\n");
5074 return E_OUTOFMEMORY;
5076 if(dest->vbo) {
5077 void *src;
5078 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5079 checkGLcall("glBindBufferARB");
5080 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5081 if(src) {
5082 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5084 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5085 checkGLcall("glUnmapBufferARB");
5089 /* Get a pointer into the destination vbo(create one if none exists) and
5090 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5092 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5093 CreateVBO(dest);
5096 if(dest->vbo) {
5097 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5098 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5099 if(!dest_conv) {
5100 ERR("glMapBuffer failed\n");
5101 /* Continue without storing converted vertices */
5105 /* Should I clip?
5106 * a) D3DRS_CLIPPING is enabled
5107 * b) WINED3DVOP_CLIP is passed
5109 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5110 static BOOL warned = FALSE;
5112 * The clipping code is not quite correct. Some things need
5113 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5114 * so disable clipping for now.
5115 * (The graphics in Half-Life are broken, and my processvertices
5116 * test crashes with IDirect3DDevice3)
5117 doClip = TRUE;
5119 doClip = FALSE;
5120 if(!warned) {
5121 warned = TRUE;
5122 FIXME("Clipping is broken and disabled for now\n");
5124 } else doClip = FALSE;
5125 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5126 if(dest_conv) {
5127 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5130 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5131 WINED3DTS_VIEW,
5132 &view_mat);
5133 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5134 WINED3DTS_PROJECTION,
5135 &proj_mat);
5136 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5137 WINED3DTS_WORLDMATRIX(0),
5138 &world_mat);
5140 TRACE("View mat:\n");
5141 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); \
5142 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); \
5143 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); \
5144 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); \
5146 TRACE("Proj mat:\n");
5147 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); \
5148 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); \
5149 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); \
5150 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); \
5152 TRACE("World mat:\n");
5153 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); \
5154 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); \
5155 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); \
5156 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); \
5158 /* Get the viewport */
5159 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5160 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5161 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5163 multiply_matrix(&mat,&view_mat,&world_mat);
5164 multiply_matrix(&mat,&proj_mat,&mat);
5166 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5168 for (i = 0; i < dwCount; i+= 1) {
5169 unsigned int tex_index;
5171 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5172 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5173 /* The position first */
5174 float *p =
5175 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5176 float x, y, z, rhw;
5177 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5179 /* Multiplication with world, view and projection matrix */
5180 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);
5181 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);
5182 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);
5183 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);
5185 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5187 /* WARNING: The following things are taken from d3d7 and were not yet checked
5188 * against d3d8 or d3d9!
5191 /* Clipping conditions: From
5192 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5194 * A vertex is clipped if it does not match the following requirements
5195 * -rhw < x <= rhw
5196 * -rhw < y <= rhw
5197 * 0 < z <= rhw
5198 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5200 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5201 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5205 if( doClip == FALSE ||
5206 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5207 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5208 ( rhw > eps ) ) ) {
5210 /* "Normal" viewport transformation (not clipped)
5211 * 1) The values are divided by rhw
5212 * 2) The y axis is negative, so multiply it with -1
5213 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5214 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5215 * 4) Multiply x with Width/2 and add Width/2
5216 * 5) The same for the height
5217 * 6) Add the viewpoint X and Y to the 2D coordinates and
5218 * The minimum Z value to z
5219 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5221 * Well, basically it's simply a linear transformation into viewport
5222 * coordinates
5225 x /= rhw;
5226 y /= rhw;
5227 z /= rhw;
5229 y *= -1;
5231 x *= vp.Width / 2;
5232 y *= vp.Height / 2;
5233 z *= vp.MaxZ - vp.MinZ;
5235 x += vp.Width / 2 + vp.X;
5236 y += vp.Height / 2 + vp.Y;
5237 z += vp.MinZ;
5239 rhw = 1 / rhw;
5240 } else {
5241 /* That vertex got clipped
5242 * Contrary to OpenGL it is not dropped completely, it just
5243 * undergoes a different calculation.
5245 TRACE("Vertex got clipped\n");
5246 x += rhw;
5247 y += rhw;
5249 x /= 2;
5250 y /= 2;
5252 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5253 * outside of the main vertex buffer memory. That needs some more
5254 * investigation...
5258 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5261 ( (float *) dest_ptr)[0] = x;
5262 ( (float *) dest_ptr)[1] = y;
5263 ( (float *) dest_ptr)[2] = z;
5264 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5266 dest_ptr += 3 * sizeof(float);
5268 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5269 dest_ptr += sizeof(float);
5272 if(dest_conv) {
5273 float w = 1 / rhw;
5274 ( (float *) dest_conv)[0] = x * w;
5275 ( (float *) dest_conv)[1] = y * w;
5276 ( (float *) dest_conv)[2] = z * w;
5277 ( (float *) dest_conv)[3] = w;
5279 dest_conv += 3 * sizeof(float);
5281 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5282 dest_conv += sizeof(float);
5286 if (DestFVF & D3DFVF_PSIZE) {
5287 dest_ptr += sizeof(DWORD);
5288 if(dest_conv) dest_conv += sizeof(DWORD);
5290 if (DestFVF & D3DFVF_NORMAL) {
5291 float *normal =
5292 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5293 /* AFAIK this should go into the lighting information */
5294 FIXME("Didn't expect the destination to have a normal\n");
5295 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5296 if(dest_conv) {
5297 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5301 if (DestFVF & D3DFVF_DIFFUSE) {
5302 DWORD *color_d =
5303 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5304 if(!color_d) {
5305 static BOOL warned = FALSE;
5307 if(warned == FALSE) {
5308 ERR("No diffuse color in source, but destination has one\n");
5309 warned = TRUE;
5312 *( (DWORD *) dest_ptr) = 0xffffffff;
5313 dest_ptr += sizeof(DWORD);
5315 if(dest_conv) {
5316 *( (DWORD *) dest_conv) = 0xffffffff;
5317 dest_conv += sizeof(DWORD);
5320 else {
5321 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5322 if(dest_conv) {
5323 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5324 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5325 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5326 dest_conv += sizeof(DWORD);
5331 if (DestFVF & D3DFVF_SPECULAR) {
5332 /* What's the color value in the feedback buffer? */
5333 DWORD *color_s =
5334 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5335 if(!color_s) {
5336 static BOOL warned = FALSE;
5338 if(warned == FALSE) {
5339 ERR("No specular color in source, but destination has one\n");
5340 warned = TRUE;
5343 *( (DWORD *) dest_ptr) = 0xFF000000;
5344 dest_ptr += sizeof(DWORD);
5346 if(dest_conv) {
5347 *( (DWORD *) dest_conv) = 0xFF000000;
5348 dest_conv += sizeof(DWORD);
5351 else {
5352 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5353 if(dest_conv) {
5354 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5355 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5356 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5357 dest_conv += sizeof(DWORD);
5362 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5363 float *tex_coord =
5364 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5365 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5366 if(!tex_coord) {
5367 ERR("No source texture, but destination requests one\n");
5368 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5369 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5371 else {
5372 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5373 if(dest_conv) {
5374 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5380 if(dest_conv) {
5381 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5382 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5385 LEAVE_GL();
5387 return WINED3D_OK;
5389 #undef copy_and_next
5391 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5393 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5394 WineDirect3DVertexStridedData strided;
5395 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5397 if (!SrcImpl) {
5398 WARN("NULL source vertex buffer\n");
5399 return WINED3DERR_INVALIDCALL;
5401 /* We don't need the source vbo because this buffer is only used as
5402 * a source for ProcessVertices. Avoid wasting resources by converting the
5403 * buffer and loading the VBO
5405 if(SrcImpl->vbo) {
5406 TRACE("Releaseing the source vbo, it won't be needed\n");
5408 if(!SrcImpl->resource.allocatedMemory) {
5409 /* Rescue the data from the buffer */
5410 void *src;
5411 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5412 if(!SrcImpl->resource.allocatedMemory) {
5413 ERR("Out of memory\n");
5414 return E_OUTOFMEMORY;
5417 ENTER_GL();
5418 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5419 checkGLcall("glBindBufferARB");
5421 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5422 if(src) {
5423 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5426 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5427 checkGLcall("glUnmapBufferARB");
5428 } else {
5429 ENTER_GL();
5432 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5433 checkGLcall("glBindBufferARB");
5434 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5435 checkGLcall("glDeleteBuffersARB");
5436 LEAVE_GL();
5438 SrcImpl->vbo = 0;
5441 memset(&strided, 0, sizeof(strided));
5442 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5444 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5447 /*****
5448 * Apply / Get / Set Texture Stage States
5449 * TODO: Verify against dx9 definitions
5450 *****/
5452 /* 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 */
5453 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5455 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5456 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5458 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5460 /* Check that the stage is within limits */
5461 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5462 TRACE("Attempt to access invalid texture rejected\n");
5463 return;
5466 ENTER_GL();
5468 switch (Type) {
5469 case WINED3DTSS_ALPHAOP :
5470 case WINED3DTSS_COLOROP :
5471 /* nothing to do as moved to drawprim for now */
5472 break;
5473 case WINED3DTSS_ADDRESSW :
5474 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5475 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5476 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5478 } else {
5479 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5480 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5481 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5482 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5484 #endif
5485 case WINED3DTSS_TEXCOORDINDEX :
5487 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5489 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5490 one flag, you can still specify an index value, which the system uses to
5491 determine the texture wrapping mode.
5492 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5493 means use the vertex position (camera-space) as the input texture coordinates
5494 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5495 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5496 to the TEXCOORDINDEX value */
5499 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5501 switch (Value & 0xFFFF0000) {
5502 case D3DTSS_TCI_PASSTHRU:
5503 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5504 glDisable(GL_TEXTURE_GEN_S);
5505 glDisable(GL_TEXTURE_GEN_T);
5506 glDisable(GL_TEXTURE_GEN_R);
5507 glDisable(GL_TEXTURE_GEN_Q);
5508 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5509 break;
5511 case D3DTSS_TCI_CAMERASPACEPOSITION:
5512 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5513 as the input texture coordinates for this stage's texture transformation. This
5514 equates roughly to EYE_LINEAR */
5516 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5517 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5518 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5519 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5520 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5522 glMatrixMode(GL_MODELVIEW);
5523 glPushMatrix();
5524 glLoadIdentity();
5525 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5526 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5527 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5528 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5529 glPopMatrix();
5531 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5532 glEnable(GL_TEXTURE_GEN_S);
5533 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5534 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5535 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5536 glEnable(GL_TEXTURE_GEN_T);
5537 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5538 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5539 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5540 glEnable(GL_TEXTURE_GEN_R);
5541 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5542 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5543 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5545 break;
5547 case D3DTSS_TCI_CAMERASPACENORMAL:
5549 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5550 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5551 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5552 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5553 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5554 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5556 glMatrixMode(GL_MODELVIEW);
5557 glPushMatrix();
5558 glLoadIdentity();
5559 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5560 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5561 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5562 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5563 glPopMatrix();
5565 glEnable(GL_TEXTURE_GEN_S);
5566 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5567 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5568 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5569 glEnable(GL_TEXTURE_GEN_T);
5570 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5571 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5572 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5573 glEnable(GL_TEXTURE_GEN_R);
5574 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5575 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5576 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5579 break;
5581 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5583 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5584 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5585 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5586 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5587 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5588 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5590 glMatrixMode(GL_MODELVIEW);
5591 glPushMatrix();
5592 glLoadIdentity();
5593 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5594 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5595 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5596 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5597 glPopMatrix();
5599 glEnable(GL_TEXTURE_GEN_S);
5600 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5601 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5602 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5603 glEnable(GL_TEXTURE_GEN_T);
5604 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5605 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5606 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5607 glEnable(GL_TEXTURE_GEN_R);
5608 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5609 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5610 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5613 break;
5615 /* Unhandled types: */
5616 default:
5617 /* Todo: */
5618 /* ? disable GL_TEXTURE_GEN_n ? */
5619 glDisable(GL_TEXTURE_GEN_S);
5620 glDisable(GL_TEXTURE_GEN_T);
5621 glDisable(GL_TEXTURE_GEN_R);
5622 glDisable(GL_TEXTURE_GEN_Q);
5623 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5624 break;
5627 break;
5629 /* Unhandled */
5630 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5631 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);
5632 break;
5634 case WINED3DTSS_BUMPENVMAT00 :
5635 case WINED3DTSS_BUMPENVMAT01 :
5636 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5637 break;
5638 case WINED3DTSS_BUMPENVMAT10 :
5639 case WINED3DTSS_BUMPENVMAT11 :
5640 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5641 break;
5643 case WINED3DTSS_BUMPENVLSCALE :
5644 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5645 break;
5647 case WINED3DTSS_BUMPENVLOFFSET :
5648 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5649 break;
5651 case WINED3DTSS_RESULTARG :
5652 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5653 break;
5655 default:
5656 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5657 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5660 LEAVE_GL();
5662 return;
5665 /*****
5666 * Get / Set Texture Stage States
5667 * TODO: Verify against dx9 definitions
5668 *****/
5669 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5672 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5674 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5676 /* Reject invalid texture units */
5677 if (Stage >= GL_LIMITS(texture_stages)) {
5678 TRACE("Attempt to access invalid texture rejected\n");
5679 return WINED3DERR_INVALIDCALL;
5682 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5683 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5684 This->updateStateBlock->textureState[Stage][Type] = Value;
5686 return WINED3D_OK;
5689 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5691 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5692 *pValue = This->updateStateBlock->textureState[Stage][Type];
5693 return WINED3D_OK;
5696 /*****
5697 * Get / Set Texture
5698 *****/
5699 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5702 IWineD3DBaseTexture *oldTexture;
5704 oldTexture = This->updateStateBlock->textures[Stage];
5705 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5707 #if 0 /* TODO: check so vertex textures */
5708 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5709 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5710 return WINED3D_OK;
5712 #endif
5714 /* Reject invalid texture units */
5715 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5716 WARN("Attempt to access invalid texture rejected\n");
5717 return WINED3DERR_INVALIDCALL;
5720 if(pTexture != NULL) {
5721 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5723 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5724 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5725 return WINED3DERR_INVALIDCALL;
5729 oldTexture = This->updateStateBlock->textures[Stage];
5730 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5731 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5733 This->updateStateBlock->set.textures[Stage] = TRUE;
5734 This->updateStateBlock->changed.textures[Stage] = TRUE;
5735 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5736 This->updateStateBlock->textures[Stage] = pTexture;
5738 /* Handle recording of state blocks */
5739 if (This->isRecordingState) {
5740 TRACE("Recording... not performing anything\n");
5741 return WINED3D_OK;
5744 /** NOTE: MSDN says that setTexture increases the reference count,
5745 * and the the application nust set the texture back to null (or have a leaky application),
5746 * This means we should pass the refcount up to the parent
5747 *******************************/
5748 if (NULL != This->updateStateBlock->textures[Stage]) {
5749 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5752 if (NULL != oldTexture) {
5753 IWineD3DBaseTexture_Release(oldTexture);
5756 /* Reset color keying */
5757 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5758 BOOL enable_ckey = FALSE;
5760 if(pTexture) {
5761 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5762 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5765 if(enable_ckey) {
5766 glAlphaFunc(GL_NOTEQUAL, 0.0);
5767 checkGLcall("glAlphaFunc");
5771 return WINED3D_OK;
5774 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5778 /* Reject invalid texture units */
5779 if (Stage >= GL_LIMITS(sampler_stages)) {
5780 TRACE("Attempt to access invalid texture rejected\n");
5781 return WINED3DERR_INVALIDCALL;
5783 *ppTexture=This->updateStateBlock->textures[Stage];
5784 if (*ppTexture)
5785 IWineD3DBaseTexture_AddRef(*ppTexture);
5786 else
5787 return WINED3DERR_INVALIDCALL;
5788 return WINED3D_OK;
5791 /*****
5792 * Get Back Buffer
5793 *****/
5794 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5795 IWineD3DSurface **ppBackBuffer) {
5796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5797 IWineD3DSwapChain *swapChain;
5798 HRESULT hr;
5800 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5802 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5803 if (hr == WINED3D_OK) {
5804 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5805 IWineD3DSwapChain_Release(swapChain);
5806 } else {
5807 *ppBackBuffer = NULL;
5809 return hr;
5812 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5814 WARN("(%p) : stub, calling idirect3d for now\n", This);
5815 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5818 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5820 IWineD3DSwapChain *swapChain;
5821 HRESULT hr;
5823 if(iSwapChain > 0) {
5824 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5825 if (hr == WINED3D_OK) {
5826 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5827 IWineD3DSwapChain_Release(swapChain);
5828 } else {
5829 FIXME("(%p) Error getting display mode\n", This);
5831 } else {
5832 /* Don't read the real display mode,
5833 but return the stored mode instead. X11 can't change the color
5834 depth, and some apps are pretty angry if they SetDisplayMode from
5835 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5837 Also don't relay to the swapchain because with ddraw it's possible
5838 that there isn't a swapchain at all */
5839 pMode->Width = This->ddraw_width;
5840 pMode->Height = This->ddraw_height;
5841 pMode->Format = This->ddraw_format;
5842 pMode->RefreshRate = 0;
5843 hr = WINED3D_OK;
5846 return hr;
5849 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5851 TRACE("(%p)->(%p)\n", This, hWnd);
5853 This->ddraw_window = hWnd;
5854 return WINED3D_OK;
5857 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5859 TRACE("(%p)->(%p)\n", This, hWnd);
5861 *hWnd = This->ddraw_window;
5862 return WINED3D_OK;
5865 /*****
5866 * Stateblock related functions
5867 *****/
5869 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5871 IWineD3DStateBlockImpl *object;
5872 HRESULT temp_result;
5874 TRACE("(%p)", This);
5876 if (This->isRecordingState) {
5877 return WINED3DERR_INVALIDCALL;
5880 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5881 if (NULL == object ) {
5882 FIXME("(%p)Error allocating memory for stateblock\n", This);
5883 return E_OUTOFMEMORY;
5885 TRACE("(%p) created object %p\n", This, object);
5886 object->wineD3DDevice= This;
5887 /** FIXME: object->parent = parent; **/
5888 object->parent = NULL;
5889 object->blockType = WINED3DSBT_ALL;
5890 object->ref = 1;
5891 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5893 temp_result = allocate_shader_constants(object);
5894 if (WINED3D_OK != temp_result)
5895 return temp_result;
5897 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5898 This->updateStateBlock = object;
5899 This->isRecordingState = TRUE;
5901 TRACE("(%p) recording stateblock %p\n",This , object);
5902 return WINED3D_OK;
5905 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5908 if (!This->isRecordingState) {
5909 FIXME("(%p) not recording! returning error\n", This);
5910 *ppStateBlock = NULL;
5911 return WINED3DERR_INVALIDCALL;
5914 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5915 This->isRecordingState = FALSE;
5916 This->updateStateBlock = This->stateBlock;
5917 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5918 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5919 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5920 return WINED3D_OK;
5923 /*****
5924 * Scene related functions
5925 *****/
5926 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5927 /* At the moment we have no need for any functionality at the beginning
5928 of a scene */
5929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5930 TRACE("(%p) : stub\n", This);
5931 return WINED3D_OK;
5934 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5936 TRACE("(%p)\n", This);
5937 ENTER_GL();
5938 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5939 glFlush();
5940 checkGLcall("glFlush");
5942 TRACE("End Scene\n");
5943 if(This->renderTarget != NULL) {
5945 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5946 IUnknown *targetContainer = NULL;
5947 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5948 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5949 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5950 /** always dirtify for now. we must find a better way to see that surface have been modified
5951 (Modifications should will only occur via draw-primitive, but we do need better locking
5952 switching to render-to-texture should remove the overhead though.
5954 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5955 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5956 IWineD3DSurface_PreLoad(This->renderTarget);
5957 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5958 IUnknown_Release(targetContainer);
5961 This->sceneEnded = TRUE;
5962 LEAVE_GL();
5963 return WINED3D_OK;
5966 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5967 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5968 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5970 IWineD3DSwapChain *swapChain = NULL;
5971 int i;
5972 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5974 TRACE("(%p) Presenting the frame\n", This);
5976 for(i = 0 ; i < swapchains ; i ++) {
5978 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5979 TRACE("presentinng chain %d, %p\n", i, swapChain);
5980 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5981 IWineD3DSwapChain_Release(swapChain);
5984 return WINED3D_OK;
5987 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5988 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5991 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5992 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5993 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5994 GLbitfield glMask = 0;
5995 GLboolean old_ztest;
5996 GLfloat old_z_clear_value;
5997 GLint old_stencil_clear_value;
5998 GLfloat old_color_clear_value[4];
5999 unsigned int i;
6000 CONST D3DRECT* curRect;
6002 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
6003 Count, pRects, Flags, Z, Stencil);
6005 ENTER_GL();
6007 glEnable(GL_SCISSOR_TEST);
6008 checkGLcall("glEnable GL_SCISSOR_TEST");
6010 if (Count > 0 && pRects) {
6011 curRect = pRects;
6012 } else {
6013 curRect = NULL;
6016 /* Only set the values up once, as they are not changing */
6017 if (Flags & D3DCLEAR_STENCIL) {
6018 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6019 glClearStencil(Stencil);
6020 checkGLcall("glClearStencil");
6021 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6022 glStencilMask(0xFFFFFFFF);
6025 if (Flags & D3DCLEAR_ZBUFFER) {
6026 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6027 glDepthMask(GL_TRUE);
6028 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6029 glClearDepth(Z);
6030 checkGLcall("glClearDepth");
6031 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6034 if (Flags & D3DCLEAR_TARGET) {
6035 TRACE("Clearing screen with glClear to color %lx\n", Color);
6036 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6037 glClearColor(D3DCOLOR_R(Color),
6038 D3DCOLOR_G(Color),
6039 D3DCOLOR_B(Color),
6040 D3DCOLOR_A(Color));
6041 checkGLcall("glClearColor");
6043 /* Clear ALL colors! */
6044 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6045 glMask = glMask | GL_COLOR_BUFFER_BIT;
6048 /* Now process each rect in turn */
6049 for (i = 0; i < Count || i == 0; i++) {
6051 if (curRect) {
6052 /* Note gl uses lower left, width/height */
6053 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
6054 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6055 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6056 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6057 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6058 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6059 checkGLcall("glScissor");
6060 } else {
6061 glScissor(This->stateBlock->viewport.X,
6062 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6063 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6064 This->stateBlock->viewport.Width,
6065 This->stateBlock->viewport.Height);
6066 checkGLcall("glScissor");
6069 /* Clear the selected rectangle (or full screen) */
6070 glClear(glMask);
6071 checkGLcall("glClear");
6073 /* Step to the next rectangle */
6074 if (curRect) curRect = curRect + sizeof(D3DRECT);
6077 /* Restore the old values (why..?) */
6078 if (Flags & D3DCLEAR_STENCIL) {
6079 glClearStencil(old_stencil_clear_value);
6080 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6082 if (Flags & D3DCLEAR_ZBUFFER) {
6083 glDepthMask(old_ztest);
6084 glClearDepth(old_z_clear_value);
6086 if (Flags & D3DCLEAR_TARGET) {
6087 glClearColor(old_color_clear_value[0],
6088 old_color_clear_value[1],
6089 old_color_clear_value[2],
6090 old_color_clear_value[3]);
6091 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6092 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6093 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6094 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6097 glDisable(GL_SCISSOR_TEST);
6098 checkGLcall("glDisable");
6099 LEAVE_GL();
6101 return WINED3D_OK;
6104 /*****
6105 * Drawing functions
6106 *****/
6107 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6108 UINT PrimitiveCount) {
6110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6111 This->stateBlock->streamIsUP = FALSE;
6113 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6114 debug_d3dprimitivetype(PrimitiveType),
6115 StartVertex, PrimitiveCount);
6116 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6117 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6120 return WINED3D_OK;
6123 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6124 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6125 D3DPRIMITIVETYPE PrimitiveType,
6126 INT baseVIndex, UINT minIndex,
6127 UINT NumVertices, UINT startIndex, UINT primCount) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6130 UINT idxStride = 2;
6131 IWineD3DIndexBuffer *pIB;
6132 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6134 pIB = This->stateBlock->pIndexData;
6135 This->stateBlock->streamIsUP = FALSE;
6137 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6138 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6139 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6141 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6142 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6143 idxStride = 2;
6144 } else {
6145 idxStride = 4;
6148 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6149 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6151 return WINED3D_OK;
6154 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6155 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6156 UINT VertexStreamZeroStride) {
6157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6159 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6160 debug_d3dprimitivetype(PrimitiveType),
6161 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6163 /* release the stream source */
6164 if (This->stateBlock->streamSource[0] != NULL) {
6165 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6168 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6169 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6170 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6171 This->stateBlock->streamIsUP = TRUE;
6173 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6174 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6176 /* MSDN specifies stream zero settings must be set to NULL */
6177 This->stateBlock->streamStride[0] = 0;
6178 This->stateBlock->streamSource[0] = NULL;
6180 /*stream zero settings set to null at end, as per the msdn */
6181 return WINED3D_OK;
6184 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6185 UINT MinVertexIndex, UINT NumVertices,
6186 UINT PrimitiveCount, CONST void* pIndexData,
6187 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6188 UINT VertexStreamZeroStride) {
6189 int idxStride;
6190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6192 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6193 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6194 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6195 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6197 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6198 idxStride = 2;
6199 } else {
6200 idxStride = 4;
6203 /* release the stream and index data */
6204 if (This->stateBlock->streamSource[0] != NULL) {
6205 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6207 if (This->stateBlock->pIndexData) {
6208 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6211 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6212 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6213 This->stateBlock->streamIsUP = TRUE;
6214 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6216 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6218 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6219 This->stateBlock->streamSource[0] = NULL;
6220 This->stateBlock->streamStride[0] = 0;
6221 This->stateBlock->pIndexData = NULL;
6223 return WINED3D_OK;
6226 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6228 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6229 return WINED3D_OK;
6231 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6232 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6234 HRESULT hr = WINED3D_OK;
6235 WINED3DRESOURCETYPE sourceType;
6236 WINED3DRESOURCETYPE destinationType;
6237 int i ,levels;
6239 /* TODO: think about moving the code into IWineD3DBaseTexture */
6241 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6243 /* verify that the source and destination textures aren't NULL */
6244 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6245 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6246 This, pSourceTexture, pDestinationTexture);
6247 hr = WINED3DERR_INVALIDCALL;
6250 if (pSourceTexture == pDestinationTexture) {
6251 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6252 This, pSourceTexture, pDestinationTexture);
6253 hr = WINED3DERR_INVALIDCALL;
6255 /* Verify that the source and destination textures are the same type */
6256 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6257 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6259 if (sourceType != destinationType) {
6260 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6261 This);
6262 hr = WINED3DERR_INVALIDCALL;
6265 /* check that both textures have the identical numbers of levels */
6266 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6267 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6268 hr = WINED3DERR_INVALIDCALL;
6271 if (WINED3D_OK == hr) {
6273 /* Make sure that the destination texture is loaded */
6274 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6276 /* Update every surface level of the texture */
6277 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6279 switch (sourceType) {
6280 case WINED3DRTYPE_TEXTURE:
6282 IWineD3DSurface *srcSurface;
6283 IWineD3DSurface *destSurface;
6285 for (i = 0 ; i < levels ; ++i) {
6286 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6287 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6288 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6289 IWineD3DSurface_Release(srcSurface);
6290 IWineD3DSurface_Release(destSurface);
6291 if (WINED3D_OK != hr) {
6292 WARN("(%p) : Call to update surface failed\n", This);
6293 return hr;
6297 break;
6298 case WINED3DRTYPE_CUBETEXTURE:
6300 IWineD3DSurface *srcSurface;
6301 IWineD3DSurface *destSurface;
6302 WINED3DCUBEMAP_FACES faceType;
6304 for (i = 0 ; i < levels ; ++i) {
6305 /* Update each cube face */
6306 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6307 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6308 if (WINED3D_OK != hr) {
6309 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6310 } else {
6311 TRACE("Got srcSurface %p\n", srcSurface);
6313 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6314 if (WINED3D_OK != hr) {
6315 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6316 } else {
6317 TRACE("Got desrSurface %p\n", destSurface);
6319 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6320 IWineD3DSurface_Release(srcSurface);
6321 IWineD3DSurface_Release(destSurface);
6322 if (WINED3D_OK != hr) {
6323 WARN("(%p) : Call to update surface failed\n", This);
6324 return hr;
6329 break;
6330 #if 0 /* TODO: Add support for volume textures */
6331 case WINED3DRTYPE_VOLUMETEXTURE:
6333 IWineD3DVolume srcVolume = NULL;
6334 IWineD3DSurface destVolume = NULL;
6336 for (i = 0 ; i < levels ; ++i) {
6337 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6338 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6339 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6340 IWineD3DVolume_Release(srcSurface);
6341 IWineD3DVolume_Release(destSurface);
6342 if (WINED3D_OK != hr) {
6343 WARN("(%p) : Call to update volume failed\n", This);
6344 return hr;
6348 break;
6349 #endif
6350 default:
6351 FIXME("(%p) : Unsupported source and destination type\n", This);
6352 hr = WINED3DERR_INVALIDCALL;
6356 return hr;
6359 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6360 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6361 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6364 TRACE("(%p) : stub\n", This);
6365 return WINED3D_OK;
6367 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6369 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6370 * NOTE It may be best to move the code into surface to occomplish this
6371 ****************************************/
6373 WINED3DSURFACE_DESC surfaceDesc;
6374 unsigned int surfaceWidth, surfaceHeight;
6375 glDescriptor *targetGlDescription = NULL;
6376 glDescriptor *surfaceGlDescription = NULL;
6377 IWineD3DSwapChainImpl *container = NULL;
6379 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6380 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6381 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6383 surfaceDesc.Width = &surfaceWidth;
6384 surfaceDesc.Height = &surfaceHeight;
6385 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6386 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6388 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6389 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6390 ENTER_GL();
6391 /* TODO: opengl Context switching for swapchains etc... */
6392 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6393 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6394 glReadBuffer(GL_BACK);
6395 vcheckGLcall("glReadBuffer(GL_BACK)");
6396 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6397 glReadBuffer(GL_FRONT);
6398 vcheckGLcall("glReadBuffer(GL_FRONT)");
6399 } else if (pRenderTarget == This->depthStencilBuffer) {
6400 FIXME("Reading of depthstencil not yet supported\n");
6403 glReadPixels(surfaceGlDescription->target,
6404 surfaceGlDescription->level,
6405 surfaceWidth,
6406 surfaceHeight,
6407 surfaceGlDescription->glFormat,
6408 surfaceGlDescription->glType,
6409 (void *)IWineD3DSurface_GetData(pSurface));
6410 vcheckGLcall("glReadPixels(...)");
6411 if(NULL != container ){
6412 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6414 } else {
6415 IWineD3DBaseTexture *container;
6416 GLenum textureDimensions = GL_TEXTURE_2D;
6418 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6419 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6420 IWineD3DBaseTexture_Release(container);
6422 /* TODO: 2D -> Cube surface coppies etc.. */
6423 if (surfaceGlDescription->target != textureDimensions) {
6424 FIXME("(%p) : Texture dimension mismatch\n", This);
6426 glEnable(textureDimensions);
6427 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6428 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6429 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6430 vcheckGLcall("glBindTexture");
6431 glGetTexImage(surfaceGlDescription->target,
6432 surfaceGlDescription->level,
6433 surfaceGlDescription->glFormat,
6434 surfaceGlDescription->glType,
6435 (void *)IWineD3DSurface_GetData(pSurface));
6436 glDisable(textureDimensions);
6437 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6440 LEAVE_GL();
6441 return WINED3D_OK;
6444 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6445 IWineD3DSwapChain *swapChain;
6446 HRESULT hr;
6447 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6448 if(hr == WINED3D_OK) {
6449 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6450 IWineD3DSwapChain_Release(swapChain);
6452 return hr;
6455 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6457 /* return a sensible default */
6458 *pNumPasses = 1;
6459 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6460 FIXME("(%p) : stub\n", This);
6461 return WINED3D_OK;
6464 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6466 int j;
6467 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6468 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6469 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6470 return WINED3DERR_INVALIDCALL;
6472 for (j = 0; j < 256; ++j) {
6473 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6474 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6475 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6476 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6478 TRACE("(%p) : returning\n", This);
6479 return WINED3D_OK;
6482 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6484 int j;
6485 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6486 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6487 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6488 return WINED3DERR_INVALIDCALL;
6490 for (j = 0; j < 256; ++j) {
6491 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6492 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6493 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6494 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6496 TRACE("(%p) : returning\n", This);
6497 return WINED3D_OK;
6500 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6502 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6503 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6504 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6505 return WINED3DERR_INVALIDCALL;
6507 /*TODO: stateblocks */
6508 This->currentPalette = PaletteNumber;
6509 TRACE("(%p) : returning\n", This);
6510 return WINED3D_OK;
6513 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6515 if (PaletteNumber == NULL) {
6516 WARN("(%p) : returning Invalid Call\n", This);
6517 return WINED3DERR_INVALIDCALL;
6519 /*TODO: stateblocks */
6520 *PaletteNumber = This->currentPalette;
6521 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6522 return WINED3D_OK;
6525 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6527 static BOOL showFixmes = TRUE;
6528 if (showFixmes) {
6529 FIXME("(%p) : stub\n", This);
6530 showFixmes = FALSE;
6533 This->softwareVertexProcessing = bSoftware;
6534 return WINED3D_OK;
6538 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6540 static BOOL showFixmes = TRUE;
6541 if (showFixmes) {
6542 FIXME("(%p) : stub\n", This);
6543 showFixmes = FALSE;
6545 return This->softwareVertexProcessing;
6549 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6551 IWineD3DSwapChain *swapChain;
6552 HRESULT hr;
6554 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6556 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6557 if(hr == WINED3D_OK){
6558 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6559 IWineD3DSwapChain_Release(swapChain);
6560 }else{
6561 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6563 return hr;
6567 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6569 static BOOL showfixmes = TRUE;
6570 if(nSegments != 0.0f) {
6571 if( showfixmes) {
6572 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6573 showfixmes = FALSE;
6576 return WINED3D_OK;
6579 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6581 static BOOL showfixmes = TRUE;
6582 if( showfixmes) {
6583 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6584 showfixmes = FALSE;
6586 return 0.0f;
6589 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6591 /** TODO: remove casts to IWineD3DSurfaceImpl
6592 * NOTE: move code to surface to accomplish this
6593 ****************************************/
6594 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6595 int srcWidth, srcHeight;
6596 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6597 WINED3DFORMAT destFormat, srcFormat;
6598 UINT destSize;
6599 int destLeft, destTop;
6600 WINED3DPOOL srcPool, destPool;
6601 int offset = 0;
6602 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6603 glDescriptor *glDescription = NULL;
6604 GLenum textureDimensions = GL_TEXTURE_2D;
6605 IWineD3DBaseTexture *baseTexture;
6607 WINED3DSURFACE_DESC winedesc;
6609 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6610 memset(&winedesc, 0, sizeof(winedesc));
6611 winedesc.Width = &srcSurfaceWidth;
6612 winedesc.Height = &srcSurfaceHeight;
6613 winedesc.Pool = &srcPool;
6614 winedesc.Format = &srcFormat;
6616 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6618 winedesc.Width = &destSurfaceWidth;
6619 winedesc.Height = &destSurfaceHeight;
6620 winedesc.Pool = &destPool;
6621 winedesc.Format = &destFormat;
6622 winedesc.Size = &destSize;
6624 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6626 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6627 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6628 return WINED3DERR_INVALIDCALL;
6631 if (destFormat == WINED3DFMT_UNKNOWN) {
6632 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6633 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6635 /* Get the update surface description */
6636 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6639 /* Make sure the surface is loaded and up to date */
6640 IWineD3DSurface_PreLoad(pDestinationSurface);
6642 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6644 ENTER_GL();
6646 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6647 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6648 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6649 destLeft = pDestPoint ? pDestPoint->x : 0;
6650 destTop = pDestPoint ? pDestPoint->y : 0;
6653 /* This function doesn't support compressed textures
6654 the pitch is just bytesPerPixel * width */
6655 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6656 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6657 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6658 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6660 /* TODO DXT formats */
6662 if(pSourceRect != NULL && pSourceRect->top != 0){
6663 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6665 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6666 ,This
6667 ,glDescription->level
6668 ,destLeft
6669 ,destTop
6670 ,srcWidth
6671 ,srcHeight
6672 ,glDescription->glFormat
6673 ,glDescription->glType
6674 ,IWineD3DSurface_GetData(pSourceSurface)
6677 /* Sanity check */
6678 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6680 /* need to lock the surface to get the data */
6681 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6684 /* TODO: Cube and volume support */
6685 if(rowoffset != 0){
6686 /* not a whole row so we have to do it a line at a time */
6687 int j;
6689 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6690 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6692 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6694 glTexSubImage2D(glDescription->target
6695 ,glDescription->level
6696 ,destLeft
6698 ,srcWidth
6700 ,glDescription->glFormat
6701 ,glDescription->glType
6702 ,data /* could be quicker using */
6704 data += rowoffset;
6707 } else { /* Full width, so just write out the whole texture */
6709 if (WINED3DFMT_DXT1 == destFormat ||
6710 WINED3DFMT_DXT2 == destFormat ||
6711 WINED3DFMT_DXT3 == destFormat ||
6712 WINED3DFMT_DXT4 == destFormat ||
6713 WINED3DFMT_DXT5 == destFormat) {
6714 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6715 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6716 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6717 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6718 } if (destFormat != srcFormat) {
6719 FIXME("Updating mixed format compressed texture is not curretly support\n");
6720 } else {
6721 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6722 glDescription->level,
6723 glDescription->glFormatInternal,
6724 srcWidth,
6725 srcHeight,
6727 destSize,
6728 IWineD3DSurface_GetData(pSourceSurface));
6730 } else {
6731 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6735 } else {
6736 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6738 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6739 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6740 data returned by GetData non-power2 width/height with hardware non-power2
6741 pow2Width/height are set to surface width height, repacking isn't needed so it
6742 doesn't matter which function gets called. */
6743 glTexSubImage2D(glDescription->target
6744 ,glDescription->level
6745 ,destLeft
6746 ,destTop
6747 ,srcWidth
6748 ,srcHeight
6749 ,glDescription->glFormat
6750 ,glDescription->glType
6751 ,IWineD3DSurface_GetData(pSourceSurface)
6753 } else {
6755 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6756 glTexSubImage2D(glDescription->target
6757 ,glDescription->level
6758 ,destLeft
6759 ,destTop
6760 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6761 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6762 ,glDescription->glFormat
6763 ,glDescription->glType
6764 ,IWineD3DSurface_GetData(pSourceSurface)
6770 checkGLcall("glTexSubImage2D");
6771 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6773 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6774 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6775 * surface bigger than it needs to be hmm.. */
6776 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6777 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6778 IWineD3DBaseTexture_Release(baseTexture);
6781 glDisable(textureDimensions); /* This needs to be managed better.... */
6782 LEAVE_GL();
6784 return WINED3D_OK;
6787 /* Used by DirectX 8 */
6788 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6789 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6790 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6793 HRESULT hr = WINED3D_OK;
6794 WINED3DFORMAT srcFormat, destFormat;
6795 UINT srcWidth, destWidth;
6796 UINT srcHeight, destHeight;
6797 UINT srcSize;
6798 WINED3DSURFACE_DESC winedesc;
6800 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6801 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6804 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6805 memset(&winedesc, 0, sizeof(winedesc));
6807 winedesc.Format = &srcFormat;
6808 winedesc.Width = &srcWidth;
6809 winedesc.Height = &srcHeight;
6810 winedesc.Size = &srcSize;
6811 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6813 winedesc.Format = &destFormat;
6814 winedesc.Width = &destWidth;
6815 winedesc.Height = &destHeight;
6816 winedesc.Size = NULL;
6817 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6819 /* Check that the source and destination formats match */
6820 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6821 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6822 return WINED3DERR_INVALIDCALL;
6823 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6824 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6825 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6826 destFormat = srcFormat;
6829 /* Quick if complete copy ... */
6830 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6832 if (srcWidth == destWidth && srcHeight == destHeight) {
6833 WINED3DLOCKED_RECT lrSrc;
6834 WINED3DLOCKED_RECT lrDst;
6835 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6836 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6837 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6839 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6841 IWineD3DSurface_UnlockRect(pSourceSurface);
6842 IWineD3DSurface_UnlockRect(pDestinationSurface);
6843 TRACE("Unlocked src and dst\n");
6845 } else {
6847 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6848 hr = WINED3DERR_INVALIDCALL;
6851 } else {
6853 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6855 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6856 unsigned int i;
6858 /* Copy rect by rect */
6859 for (i = 0; i < cRects; ++i) {
6860 CONST RECT* r = &pSourceRectsArray[i];
6861 CONST POINT* p = &pDestPointsArray[i];
6862 int copyperline;
6863 int j;
6864 WINED3DLOCKED_RECT lrSrc;
6865 WINED3DLOCKED_RECT lrDst;
6866 RECT dest_rect;
6868 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6869 if (srcFormat == WINED3DFMT_DXT1) {
6870 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6871 } else {
6872 copyperline = ((r->right - r->left) * bytesPerPixel);
6875 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6876 dest_rect.left = p->x;
6877 dest_rect.top = p->y;
6878 dest_rect.right = p->x + (r->right - r->left);
6879 dest_rect.bottom= p->y + (r->bottom - r->top);
6880 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6881 TRACE("Locked src and dst\n");
6883 /* Find where to start */
6884 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6885 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6887 IWineD3DSurface_UnlockRect(pSourceSurface);
6888 IWineD3DSurface_UnlockRect(pDestinationSurface);
6889 TRACE("Unlocked src and dst\n");
6891 } else {
6892 unsigned int i;
6893 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6894 int copyperline;
6895 int j;
6896 WINED3DLOCKED_RECT lrSrc;
6897 WINED3DLOCKED_RECT lrDst;
6898 RECT dest_rect;
6900 for(i=0; i < cRects; i++) {
6901 CONST RECT* r = &pSourceRectsArray[i];
6903 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6904 if (srcFormat == WINED3DFMT_DXT1) {
6905 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6906 } else {
6907 copyperline = ((r->right - r->left) * bytesPerPixel);
6909 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6910 dest_rect.left = 0;
6911 dest_rect.top = 0;
6912 dest_rect.right = r->right - r->left;
6913 dest_rect.bottom= r->bottom - r->top;
6914 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6915 TRACE("Locked src and dst\n");
6916 /* Find where to start */
6917 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6918 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6920 IWineD3DSurface_UnlockRect(pSourceSurface);
6921 IWineD3DSurface_UnlockRect(pDestinationSurface);
6922 TRACE("Unlocked src and dst\n");
6927 return hr;
6930 /* Implementation details at http://developer.nvidia.com/attach/6494
6932 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6933 hmm.. no longer supported use
6934 OpenGL evaluators or tessellate surfaces within your application.
6937 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6938 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6940 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6941 FIXME("(%p) : Stub\n", This);
6942 return WINED3D_OK;
6946 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6947 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6949 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6950 FIXME("(%p) : Stub\n", This);
6951 return WINED3D_OK;
6954 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6956 TRACE("(%p) Handle(%d)\n", This, Handle);
6957 FIXME("(%p) : Stub\n", This);
6958 return WINED3D_OK;
6961 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6963 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6964 DDBLTFX BltFx;
6965 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6967 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6968 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6969 return WINED3DERR_INVALIDCALL;
6972 /* Just forward this to the DirectDraw blitting engine */
6973 memset(&BltFx, 0, sizeof(BltFx));
6974 BltFx.dwSize = sizeof(BltFx);
6975 BltFx.u5.dwFillColor = color;
6976 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6979 /* rendertarget and deptth stencil functions */
6980 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6983 /* FIXME: Implelent RenderTargetIndex >0 */
6984 if(RenderTargetIndex > 0)
6985 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6987 *ppRenderTarget = This->renderTarget;
6988 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6989 /* Note inc ref on returned surface */
6990 if(*ppRenderTarget != NULL)
6991 IWineD3DSurface_AddRef(*ppRenderTarget);
6992 return WINED3D_OK;
6995 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6997 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6998 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6999 IWineD3DSwapChainImpl *Swapchain;
7000 HRESULT hr;
7002 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
7004 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
7005 if(hr != WINED3D_OK) {
7006 ERR("Can't get the swapchain\n");
7007 return hr;
7010 /* Make sure to release the swapchain */
7011 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
7013 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
7014 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7015 return WINED3DERR_INVALIDCALL;
7017 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7018 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7019 return WINED3DERR_INVALIDCALL;
7022 if(Swapchain->frontBuffer != Front) {
7023 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7025 if(Swapchain->frontBuffer)
7026 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7027 Swapchain->frontBuffer = Front;
7029 if(Swapchain->frontBuffer) {
7030 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7034 if(Back && !Swapchain->backBuffer) {
7035 /* We need memory for the back buffer array - only one back buffer this way */
7036 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7037 if(!Swapchain->backBuffer) {
7038 ERR("Out of memory\n");
7039 return E_OUTOFMEMORY;
7043 if(Swapchain->backBuffer[0] != Back) {
7044 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7045 ENTER_GL();
7046 if(!Swapchain->backBuffer[0]) {
7047 /* GL was told to draw to the front buffer at creation,
7048 * undo that
7050 glDrawBuffer(GL_BACK);
7051 checkGLcall("glDrawBuffer(GL_BACK)");
7052 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7053 Swapchain->presentParms.BackBufferCount = 1;
7054 } else if (!Back) {
7055 /* That makes problems - disable for now */
7056 /* glDrawBuffer(GL_FRONT); */
7057 checkGLcall("glDrawBuffer(GL_FRONT)");
7058 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7059 Swapchain->presentParms.BackBufferCount = 0;
7061 LEAVE_GL();
7063 if(Swapchain->backBuffer[0])
7064 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7065 Swapchain->backBuffer[0] = Back;
7067 if(Swapchain->backBuffer[0]) {
7068 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7069 } else {
7070 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7075 return WINED3D_OK;
7078 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7080 *ppZStencilSurface = This->depthStencilBuffer;
7081 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7083 if(*ppZStencilSurface != NULL) {
7084 /* Note inc ref on returned surface */
7085 IWineD3DSurface_AddRef(*ppZStencilSurface);
7087 return WINED3D_OK;
7090 /* internal static helper functions */
7091 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7092 IWineD3DSurface *RenderSurface);
7094 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7096 HRESULT hr = WINED3D_OK;
7097 WINED3DVIEWPORT viewport;
7099 TRACE("(%p) Swapping rendertarget\n",This);
7100 if (RenderTargetIndex > 0) {
7101 FIXME("(%p) Render targets other than the first are not supported\n",This);
7102 RenderTargetIndex = 0;
7105 /* MSDN says that null disables the render target
7106 but a device must always be associated with a render target
7107 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7109 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7110 for more details
7112 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7113 FIXME("Trying to set render target 0 to NULL\n");
7114 return WINED3DERR_INVALIDCALL;
7116 /* TODO: replace Impl* usage with interface usage */
7117 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7118 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);
7119 return WINED3DERR_INVALIDCALL;
7121 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7122 * builds, but I think wine counts as a 'debug' build for now.
7123 ******************************/
7124 /* If we are trying to set what we already have, don't bother */
7125 if (pRenderTarget == This->renderTarget) {
7126 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7127 } else {
7128 /* Otherwise, set the render target up */
7130 if (FALSE == This->sceneEnded) {
7131 IWineD3DDevice_EndScene(iface);
7133 TRACE("clearing renderer\n");
7134 /* IWineD3DDeviceImpl_CleanRender(iface); */
7135 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7136 depending on the renter target implementation being used.
7137 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7138 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7139 stencil buffer and incure an extra memory overhead */
7140 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7143 if (SUCCEEDED(hr)) {
7144 /* Finally, reset the viewport as the MSDN states. */
7145 /* TODO: Replace impl usage */
7146 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7147 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7148 viewport.X = 0;
7149 viewport.Y = 0;
7150 viewport.MaxZ = 1.0f;
7151 viewport.MinZ = 0.0f;
7152 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7153 } else {
7154 FIXME("Unknown error setting the render target\n");
7156 This->sceneEnded = FALSE;
7157 return hr;
7160 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7162 HRESULT hr = WINED3D_OK;
7163 IWineD3DSurface *tmp;
7165 TRACE("(%p) Swapping z-buffer\n",This);
7167 if (pNewZStencil == This->stencilBufferTarget) {
7168 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7169 } else {
7170 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7171 * depending on the renter target implementation being used.
7172 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7173 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7174 * stencil buffer and incure an extra memory overhead
7175 ******************************************************/
7178 tmp = This->stencilBufferTarget;
7179 This->stencilBufferTarget = pNewZStencil;
7180 /* should we be calling the parent or the wined3d surface? */
7181 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7182 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7183 hr = WINED3D_OK;
7184 /** TODO: glEnable/glDisable on depth/stencil depending on
7185 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7186 **********************************************************/
7189 return hr;
7193 #ifdef GL_VERSION_1_3
7194 /* Internal functions not in DirectX */
7195 /** TODO: move this off to the opengl context manager
7196 *(the swapchain doesn't need to know anything about offscreen rendering!)
7197 ****************************************************/
7199 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7203 TRACE("(%p), %p\n", This, swapchain);
7205 if (swapchain->win != swapchain->drawable) {
7206 /* Set everything back the way it ws */
7207 swapchain->render_ctx = swapchain->glCtx;
7208 swapchain->drawable = swapchain->win;
7210 return WINED3D_OK;
7213 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7214 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7216 int i;
7217 unsigned int width;
7218 unsigned int height;
7219 WINED3DFORMAT format;
7220 WINED3DSURFACE_DESC surfaceDesc;
7221 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7222 surfaceDesc.Width = &width;
7223 surfaceDesc.Height = &height;
7224 surfaceDesc.Format = &format;
7225 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7226 *context = NULL;
7227 /* I need a get width/height function (and should do something with the format) */
7228 for (i = 0; i < CONTEXT_CACHE; ++i) {
7229 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7230 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7231 the pSurface can be set to 0 allowing it to be reused from cache **/
7232 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7233 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7234 *context = &This->contextCache[i];
7235 break;
7237 if (This->contextCache[i].Width == 0) {
7238 This->contextCache[i].pSurface = pSurface;
7239 This->contextCache[i].Width = width;
7240 This->contextCache[i].Height = height;
7241 *context = &This->contextCache[i];
7242 break;
7245 if (i == CONTEXT_CACHE) {
7246 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7247 glContext *dropContext = 0;
7248 for (i = 0; i < CONTEXT_CACHE; i++) {
7249 if (This->contextCache[i].usedcount < minUsage) {
7250 dropContext = &This->contextCache[i];
7251 minUsage = This->contextCache[i].usedcount;
7254 /* clean up the context (this doesn't work for ATI at the moment */
7255 #if 0
7256 glXDestroyContext(swapchain->display, dropContext->context);
7257 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7258 #endif
7259 FIXME("Leak\n");
7260 dropContext->Width = 0;
7261 dropContext->pSurface = pSurface;
7262 *context = dropContext;
7263 } else {
7264 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7265 for (i = 0; i < CONTEXT_CACHE; i++) {
7266 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7270 if (*context != NULL)
7271 return WINED3D_OK;
7272 else
7273 return E_OUTOFMEMORY;
7275 #endif
7277 /* Reapply the device stateblock */
7278 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7280 BOOL oldRecording;
7281 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7283 /* Disable recording */
7284 oldUpdateStateBlock = This->updateStateBlock;
7285 oldRecording= This->isRecordingState;
7286 This->isRecordingState = FALSE;
7287 This->updateStateBlock = This->stateBlock;
7289 /* Reapply the state block */
7290 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7292 /* Restore recording */
7293 This->isRecordingState = oldRecording;
7294 This->updateStateBlock = oldUpdateStateBlock;
7297 /* Set the device to render to a texture, or not.
7298 * This involves changing renderUpsideDown */
7300 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7302 DWORD cullMode;
7303 BOOL oldRecording;
7304 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7306 /* Disable recording */
7307 oldUpdateStateBlock = This->updateStateBlock;
7308 oldRecording= This->isRecordingState;
7309 This->isRecordingState = FALSE;
7310 This->updateStateBlock = This->stateBlock;
7312 /* Set upside-down rendering, and update the cull mode */
7313 /* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
7314 This->renderUpsideDown = isTexture;
7315 This->last_was_rhw = FALSE;
7316 This->proj_valid = FALSE;
7317 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7318 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7320 /* Restore recording */
7321 This->isRecordingState = oldRecording;
7322 This->updateStateBlock = oldUpdateStateBlock;
7325 /* Returns an array of compatible FBconfig(s).
7326 * The array must be freed with XFree. Requires ENTER_GL() */
7328 static GLXFBConfig* device_find_fbconfigs(
7329 IWineD3DDeviceImpl* This,
7330 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7331 IWineD3DSurface* RenderSurface) {
7333 GLXFBConfig* cfgs = NULL;
7334 int nCfgs = 0;
7335 int attribs[256];
7336 int nAttribs = 0;
7338 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7339 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7340 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7342 /**TODO:
7343 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7344 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7347 #define PUSH1(att) attribs[nAttribs++] = (att);
7348 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7350 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7352 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7353 PUSH2(GLX_X_RENDERABLE, TRUE);
7354 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7355 TRACE("calling makeglcfg\n");
7356 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7357 PUSH1(None);
7358 TRACE("calling chooseFGConfig\n");
7359 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7360 DefaultScreen(implicitSwapchainImpl->display),
7361 attribs, &nCfgs);
7362 if (cfgs == NULL) {
7363 /* OK we didn't find the exact config, so use any reasonable match */
7364 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7365 why we failed and only show this message once! */
7366 MESSAGE("Failed to find exact match, finding alternative but you may "
7367 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7368 nAttribs = 0;
7369 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7370 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7371 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7372 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7373 TRACE("calling makeglcfg\n");
7374 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7375 PUSH1(None);
7376 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7377 DefaultScreen(implicitSwapchainImpl->display),
7378 attribs, &nCfgs);
7381 if (cfgs == NULL) {
7382 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7383 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7384 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7385 } else {
7386 #ifdef EXTRA_TRACES
7387 int i;
7388 for (i = 0; i < nCfgs; ++i) {
7389 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7390 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7391 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7393 if (NULL != This->renderTarget) {
7394 glFlush();
7395 vcheckGLcall("glFlush");
7396 /** This is only useful if the old render target was a swapchain,
7397 * we need to supercede this with a function that displays
7398 * the current buffer on the screen. This is easy to do in glx1.3 but
7399 * we need to do copy-write pixels in glx 1.2.
7400 ************************************************/
7401 glXSwapBuffers(implicitSwapChainImpl->display,
7402 implicitSwapChainImpl->drawable);
7403 printf("Hit Enter to get next frame ...\n");
7404 getchar();
7406 #endif
7408 #undef PUSH1
7409 #undef PUSH2
7411 return cfgs;
7414 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7415 * the functionality needs splitting up so that we don't do more than we should do.
7416 * this only seems to impact performance a little.
7417 ******************************/
7418 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7419 IWineD3DSurface *RenderSurface) {
7422 * Currently only active for GLX >= 1.3
7423 * for others versions we'll have to use GLXPixmaps
7425 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7426 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7427 * so only check OpenGL version
7428 * ..........................
7429 * I don't believe that it is a problem with NVidia headers,
7430 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7431 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7432 * ATI Note:
7433 * Your application will report GLX version 1.2 on glXQueryVersion.
7434 * However, it is safe to call the GLX 1.3 functions as described below.
7436 #if defined(GL_VERSION_1_3)
7438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7439 IWineD3DSurface *tmp;
7440 GLXFBConfig* cfgs = NULL;
7441 IWineD3DSwapChain *currentSwapchain;
7442 IWineD3DSwapChainImpl *currentSwapchainImpl;
7443 IWineD3DSwapChain *implicitSwapchain;
7444 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7445 IWineD3DSwapChain *renderSurfaceSwapchain;
7446 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7448 /* Obtain a reference to the device implicit swapchain,
7449 * the swapchain of the current render target,
7450 * and the swapchain of the new render target.
7451 * Fallback to device implicit swapchain if the current render target doesn't have one */
7452 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7453 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7454 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
7455 if (currentSwapchain == NULL)
7456 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7458 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7459 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7460 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7462 ENTER_GL();
7465 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7466 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7467 **********************************************************************/
7468 if (renderSurfaceSwapchain != NULL) {
7470 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7471 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7472 TRACE("making swapchain active\n");
7473 if (RenderSurface != This->renderTarget) {
7474 BOOL backbuf = FALSE;
7475 int i;
7477 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7478 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7479 backbuf = TRUE;
7480 break;
7484 if (backbuf) {
7485 } else {
7486 /* This could be flagged so that some operations work directly with the front buffer */
7487 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7489 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7490 renderSurfaceSwapchainImpl->win,
7491 renderSurfaceSwapchainImpl->glCtx) == False) {
7493 TRACE("Error in setting current context: context %p drawable %ld !\n",
7494 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7496 checkGLcall("glXMakeContextCurrent");
7498 /* Clean up the old context */
7499 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7501 /* Reapply the stateblock, and set the device not to render to texture */
7502 device_reapply_stateblock(This);
7503 device_render_to_texture(This, FALSE);
7506 /* Offscreen rendering: PBuffers (currently disabled).
7507 * Also note that this path is never reached if FBOs are supported */
7508 } else if (pbuffer_support &&
7509 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7511 /** ********************************************************************
7512 * This is a quickly hacked out implementation of offscreen textures.
7513 * It will work in most cases but there may be problems if the client
7514 * modifies the texture directly, or expects the contents of the rendertarget
7515 * to be persistent.
7517 * There are some real speed vs compatibility issues here:
7518 * we should really use a new context for every texture, but that eats ram.
7519 * we should also be restoring the texture to the pbuffer but that eats CPU
7520 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7521 * but if this means reusing the display backbuffer then we need to make sure that
7522 * states are correctly preserved.
7523 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7524 * and gain a good performance increase at the cost of compatibility.
7525 * I would suggest that, when this is the case, a user configurable flag be made
7526 * available, allowing the user to choose the best emulated experience for them.
7527 *********************************************************************/
7529 XVisualInfo *visinfo;
7530 glContext *newContext;
7532 /* Here were using a shared context model */
7533 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7534 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7537 /* If the context doesn't exist then create a new one */
7538 /* TODO: This should really be part of findGlContext */
7539 if (NULL == newContext->context) {
7541 int attribs[256];
7542 int nAttribs = 0;
7544 TRACE("making new buffer\n");
7545 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7546 attribs[nAttribs++] = newContext->Width;
7547 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7548 attribs[nAttribs++] = newContext->Height;
7549 attribs[nAttribs++] = None;
7551 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7553 /** ****************************************
7554 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7555 *they note:
7556 * In future releases, we may provide the calls glXCreateNewContext,
7557 * glXQueryDrawable and glXMakeContextCurrent.
7558 * so until then we have to use glXGetVisualFromFBConfig &co..
7559 ********************************************/
7561 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7562 if (!visinfo) {
7563 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7564 } else {
7565 newContext->context = glXCreateContext(
7566 implicitSwapchainImpl->display, visinfo,
7567 implicitSwapchainImpl->glCtx, GL_TRUE);
7569 XFree(visinfo);
7572 if (NULL == newContext || NULL == newContext->context) {
7573 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7574 } else {
7575 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7576 if (glXMakeCurrent(implicitSwapchainImpl->display,
7577 newContext->drawable, newContext->context) == False) {
7579 TRACE("Error in setting current context: context %p drawable %ld\n",
7580 newContext->context, newContext->drawable);
7582 checkGLcall("glXMakeContextCurrent");
7584 /* Clean up the old context */
7585 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7587 /* Reapply stateblock, and set device to render to a texture */
7588 device_reapply_stateblock(This);
7589 device_render_to_texture(This, TRUE);
7591 /* Set the current context of the swapchain to the new context */
7592 implicitSwapchainImpl->drawable = newContext->drawable;
7593 implicitSwapchainImpl->render_ctx = newContext->context;
7597 /* Replace the render target */
7598 tmp = This->renderTarget;
7599 This->renderTarget = RenderSurface;
7600 IWineD3DSurface_AddRef(This->renderTarget);
7601 IWineD3DSurface_Release(tmp);
7603 if (cfgs != NULL) XFree(cfgs);
7604 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
7605 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7606 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7607 LEAVE_GL();
7608 #endif
7609 return WINED3D_OK;
7612 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7613 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7615 /* TODO: the use of Impl is deprecated. */
7616 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7618 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7620 /* some basic validation checks */
7621 if(This->cursorTexture) {
7622 ENTER_GL();
7623 glDeleteTextures(1, &This->cursorTexture);
7624 LEAVE_GL();
7625 This->cursorTexture = 0;
7628 if(pCursorBitmap) {
7629 /* MSDN: Cursor must be A8R8G8B8 */
7630 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7631 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7632 return WINED3DERR_INVALIDCALL;
7635 /* MSDN: Cursor must be smaller than the display mode */
7636 if(pSur->currentDesc.Width > This->ddraw_width ||
7637 pSur->currentDesc.Height > This->ddraw_height) {
7638 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);
7639 return WINED3DERR_INVALIDCALL;
7642 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7643 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7644 * Texture and Blitting code to draw the cursor
7646 pSur->Flags |= SFLAG_FORCELOAD;
7647 IWineD3DSurface_PreLoad(pCursorBitmap);
7648 pSur->Flags &= ~SFLAG_FORCELOAD;
7649 /* Do not store the surface's pointer because the application may release
7650 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7651 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7653 This->cursorTexture = pSur->glDescription.textureName;
7654 This->cursorWidth = pSur->currentDesc.Width;
7655 This->cursorHeight = pSur->currentDesc.Height;
7656 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7659 This->xHotSpot = XHotSpot;
7660 This->yHotSpot = YHotSpot;
7661 return WINED3D_OK;
7664 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7666 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7668 This->xScreenSpace = XScreenSpace;
7669 This->yScreenSpace = YScreenSpace;
7671 return;
7675 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7677 BOOL oldVisible = This->bCursorVisible;
7678 TRACE("(%p) : visible(%d)\n", This, bShow);
7680 if(This->cursorTexture)
7681 This->bCursorVisible = bShow;
7683 return oldVisible;
7686 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7688 TRACE("(%p) : state (%lu)\n", This, This->state);
7689 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7690 switch (This->state) {
7691 case WINED3D_OK:
7692 return WINED3D_OK;
7693 case WINED3DERR_DEVICELOST:
7695 ResourceList *resourceList = This->resources;
7696 while (NULL != resourceList) {
7697 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7698 return WINED3DERR_DEVICENOTRESET;
7699 resourceList = resourceList->next;
7701 return WINED3DERR_DEVICELOST;
7703 case WINED3DERR_DRIVERINTERNALERROR:
7704 return WINED3DERR_DRIVERINTERNALERROR;
7707 /* Unknown state */
7708 return WINED3DERR_DRIVERINTERNALERROR;
7712 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7714 /** FIXME: Resource tracking needs to be done,
7715 * The closes we can do to this is set the priorities of all managed textures low
7716 * and then reset them.
7717 ***********************************************************/
7718 FIXME("(%p) : stub\n", This);
7719 return WINED3D_OK;
7722 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7724 /** FIXME: Resource trascking needs to be done.
7725 * in effect this pulls all non only default
7726 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7727 * and should clear down the context and set it up according to pPresentationParameters
7728 ***********************************************************/
7729 FIXME("(%p) : stub\n", This);
7730 return WINED3D_OK;
7733 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7735 /** FIXME: always true at the moment **/
7736 if(bEnableDialogs == FALSE) {
7737 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7739 return WINED3D_OK;
7743 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7745 TRACE("(%p) : pParameters %p\n", This, pParameters);
7747 *pParameters = This->createParms;
7748 return WINED3D_OK;
7751 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7752 IWineD3DSwapChain *swapchain;
7753 HRESULT hrc = WINED3D_OK;
7755 TRACE("Relaying to swapchain\n");
7757 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7758 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7759 IWineD3DSwapChain_Release(swapchain);
7761 return;
7764 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7765 IWineD3DSwapChain *swapchain;
7766 HRESULT hrc = WINED3D_OK;
7768 TRACE("Relaying to swapchain\n");
7770 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7771 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7772 IWineD3DSwapChain_Release(swapchain);
7774 return;
7778 /** ********************************************************
7779 * Notification functions
7780 ** ********************************************************/
7781 /** This function must be called in the release of a resource when ref == 0,
7782 * the contents of resource must still be correct,
7783 * any handels to other resource held by the caller must be closed
7784 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7785 *****************************************************/
7786 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7788 ResourceList* resourceList;
7790 TRACE("(%p) : resource %p\n", This, resource);
7791 #if 0
7792 EnterCriticalSection(&resourceStoreCriticalSection);
7793 #endif
7794 /* add a new texture to the frot of the linked list */
7795 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7796 resourceList->resource = resource;
7798 /* Get the old head */
7799 resourceList->next = This->resources;
7801 This->resources = resourceList;
7802 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7804 #if 0
7805 LeaveCriticalSection(&resourceStoreCriticalSection);
7806 #endif
7807 return;
7810 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7812 ResourceList* resourceList = NULL;
7813 ResourceList* previousResourceList = NULL;
7815 TRACE("(%p) : resource %p\n", This, resource);
7817 #if 0
7818 EnterCriticalSection(&resourceStoreCriticalSection);
7819 #endif
7820 resourceList = This->resources;
7822 while (resourceList != NULL) {
7823 if(resourceList->resource == resource) break;
7824 previousResourceList = resourceList;
7825 resourceList = resourceList->next;
7828 if (resourceList == NULL) {
7829 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7830 #if 0
7831 LeaveCriticalSection(&resourceStoreCriticalSection);
7832 #endif
7833 return;
7834 } else {
7835 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7837 /* make sure we don't leave a hole in the list */
7838 if (previousResourceList != NULL) {
7839 previousResourceList->next = resourceList->next;
7840 } else {
7841 This->resources = resourceList->next;
7844 #if 0
7845 LeaveCriticalSection(&resourceStoreCriticalSection);
7846 #endif
7847 return;
7851 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7853 int counter;
7855 TRACE("(%p) : resource %p\n", This, resource);
7856 switch(IWineD3DResource_GetType(resource)){
7857 case WINED3DRTYPE_SURFACE:
7858 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7859 break;
7860 case WINED3DRTYPE_TEXTURE:
7861 case WINED3DRTYPE_CUBETEXTURE:
7862 case WINED3DRTYPE_VOLUMETEXTURE:
7863 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7864 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7865 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7866 This->stateBlock->textures[counter] = NULL;
7868 if (This->updateStateBlock != This->stateBlock ){
7869 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7870 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7871 This->updateStateBlock->textures[counter] = NULL;
7875 break;
7876 case WINED3DRTYPE_VOLUME:
7877 /* TODO: nothing really? */
7878 break;
7879 case WINED3DRTYPE_VERTEXBUFFER:
7880 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7882 int streamNumber;
7883 TRACE("Cleaning up stream pointers\n");
7885 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7886 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7887 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7889 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7890 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7891 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7892 This->updateStateBlock->streamSource[streamNumber] = 0;
7893 /* Set changed flag? */
7896 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) */
7897 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7898 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7899 This->stateBlock->streamSource[streamNumber] = 0;
7902 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7903 else { /* This shouldn't happen */
7904 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7906 #endif
7910 break;
7911 case WINED3DRTYPE_INDEXBUFFER:
7912 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7913 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7914 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7915 This->updateStateBlock->pIndexData = NULL;
7918 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7919 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7920 This->stateBlock->pIndexData = NULL;
7924 break;
7925 default:
7926 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7927 break;
7931 /* Remove the resoruce from the resourceStore */
7932 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7934 TRACE("Resource released\n");
7938 /**********************************************************
7939 * IWineD3DDevice VTbl follows
7940 **********************************************************/
7942 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7944 /*** IUnknown methods ***/
7945 IWineD3DDeviceImpl_QueryInterface,
7946 IWineD3DDeviceImpl_AddRef,
7947 IWineD3DDeviceImpl_Release,
7948 /*** IWineD3DDevice methods ***/
7949 IWineD3DDeviceImpl_GetParent,
7950 /*** Creation methods**/
7951 IWineD3DDeviceImpl_CreateVertexBuffer,
7952 IWineD3DDeviceImpl_CreateIndexBuffer,
7953 IWineD3DDeviceImpl_CreateStateBlock,
7954 IWineD3DDeviceImpl_CreateSurface,
7955 IWineD3DDeviceImpl_CreateTexture,
7956 IWineD3DDeviceImpl_CreateVolumeTexture,
7957 IWineD3DDeviceImpl_CreateVolume,
7958 IWineD3DDeviceImpl_CreateCubeTexture,
7959 IWineD3DDeviceImpl_CreateQuery,
7960 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7961 IWineD3DDeviceImpl_CreateVertexDeclaration,
7962 IWineD3DDeviceImpl_CreateVertexShader,
7963 IWineD3DDeviceImpl_CreatePixelShader,
7964 IWineD3DDeviceImpl_CreatePalette,
7965 /*** Odd functions **/
7966 IWineD3DDeviceImpl_Init3D,
7967 IWineD3DDeviceImpl_Uninit3D,
7968 IWineD3DDeviceImpl_EnumDisplayModes,
7969 IWineD3DDeviceImpl_EvictManagedResources,
7970 IWineD3DDeviceImpl_GetAvailableTextureMem,
7971 IWineD3DDeviceImpl_GetBackBuffer,
7972 IWineD3DDeviceImpl_GetCreationParameters,
7973 IWineD3DDeviceImpl_GetDeviceCaps,
7974 IWineD3DDeviceImpl_GetDirect3D,
7975 IWineD3DDeviceImpl_GetDisplayMode,
7976 IWineD3DDeviceImpl_SetDisplayMode,
7977 IWineD3DDeviceImpl_GetHWND,
7978 IWineD3DDeviceImpl_SetHWND,
7979 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7980 IWineD3DDeviceImpl_GetRasterStatus,
7981 IWineD3DDeviceImpl_GetSwapChain,
7982 IWineD3DDeviceImpl_Reset,
7983 IWineD3DDeviceImpl_SetDialogBoxMode,
7984 IWineD3DDeviceImpl_SetCursorProperties,
7985 IWineD3DDeviceImpl_SetCursorPosition,
7986 IWineD3DDeviceImpl_ShowCursor,
7987 IWineD3DDeviceImpl_TestCooperativeLevel,
7988 /*** Getters and setters **/
7989 IWineD3DDeviceImpl_SetClipPlane,
7990 IWineD3DDeviceImpl_GetClipPlane,
7991 IWineD3DDeviceImpl_SetClipStatus,
7992 IWineD3DDeviceImpl_GetClipStatus,
7993 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7994 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7995 IWineD3DDeviceImpl_SetDepthStencilSurface,
7996 IWineD3DDeviceImpl_GetDepthStencilSurface,
7997 IWineD3DDeviceImpl_SetFVF,
7998 IWineD3DDeviceImpl_GetFVF,
7999 IWineD3DDeviceImpl_SetGammaRamp,
8000 IWineD3DDeviceImpl_GetGammaRamp,
8001 IWineD3DDeviceImpl_SetIndices,
8002 IWineD3DDeviceImpl_GetIndices,
8003 IWineD3DDeviceImpl_SetLight,
8004 IWineD3DDeviceImpl_GetLight,
8005 IWineD3DDeviceImpl_SetLightEnable,
8006 IWineD3DDeviceImpl_GetLightEnable,
8007 IWineD3DDeviceImpl_SetMaterial,
8008 IWineD3DDeviceImpl_GetMaterial,
8009 IWineD3DDeviceImpl_SetNPatchMode,
8010 IWineD3DDeviceImpl_GetNPatchMode,
8011 IWineD3DDeviceImpl_SetPaletteEntries,
8012 IWineD3DDeviceImpl_GetPaletteEntries,
8013 IWineD3DDeviceImpl_SetPixelShader,
8014 IWineD3DDeviceImpl_GetPixelShader,
8015 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8016 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8017 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8018 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8019 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8020 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8021 IWineD3DDeviceImpl_SetRenderState,
8022 IWineD3DDeviceImpl_GetRenderState,
8023 IWineD3DDeviceImpl_SetRenderTarget,
8024 IWineD3DDeviceImpl_GetRenderTarget,
8025 IWineD3DDeviceImpl_SetFrontBackBuffers,
8026 IWineD3DDeviceImpl_SetSamplerState,
8027 IWineD3DDeviceImpl_GetSamplerState,
8028 IWineD3DDeviceImpl_SetScissorRect,
8029 IWineD3DDeviceImpl_GetScissorRect,
8030 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8031 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8032 IWineD3DDeviceImpl_SetStreamSource,
8033 IWineD3DDeviceImpl_GetStreamSource,
8034 IWineD3DDeviceImpl_SetStreamSourceFreq,
8035 IWineD3DDeviceImpl_GetStreamSourceFreq,
8036 IWineD3DDeviceImpl_SetTexture,
8037 IWineD3DDeviceImpl_GetTexture,
8038 IWineD3DDeviceImpl_SetTextureStageState,
8039 IWineD3DDeviceImpl_GetTextureStageState,
8040 IWineD3DDeviceImpl_SetTransform,
8041 IWineD3DDeviceImpl_GetTransform,
8042 IWineD3DDeviceImpl_SetVertexDeclaration,
8043 IWineD3DDeviceImpl_GetVertexDeclaration,
8044 IWineD3DDeviceImpl_SetVertexShader,
8045 IWineD3DDeviceImpl_GetVertexShader,
8046 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8047 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8048 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8049 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8050 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8051 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8052 IWineD3DDeviceImpl_SetViewport,
8053 IWineD3DDeviceImpl_GetViewport,
8054 IWineD3DDeviceImpl_MultiplyTransform,
8055 IWineD3DDeviceImpl_ValidateDevice,
8056 IWineD3DDeviceImpl_ProcessVertices,
8057 /*** State block ***/
8058 IWineD3DDeviceImpl_BeginStateBlock,
8059 IWineD3DDeviceImpl_EndStateBlock,
8060 /*** Scene management ***/
8061 IWineD3DDeviceImpl_BeginScene,
8062 IWineD3DDeviceImpl_EndScene,
8063 IWineD3DDeviceImpl_Present,
8064 IWineD3DDeviceImpl_Clear,
8065 /*** Drawing ***/
8066 IWineD3DDeviceImpl_DrawPrimitive,
8067 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8068 IWineD3DDeviceImpl_DrawPrimitiveUP,
8069 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8070 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8071 IWineD3DDeviceImpl_DrawRectPatch,
8072 IWineD3DDeviceImpl_DrawTriPatch,
8073 IWineD3DDeviceImpl_DeletePatch,
8074 IWineD3DDeviceImpl_ColorFill,
8075 IWineD3DDeviceImpl_UpdateTexture,
8076 IWineD3DDeviceImpl_UpdateSurface,
8077 IWineD3DDeviceImpl_CopyRects,
8078 IWineD3DDeviceImpl_StretchRect,
8079 IWineD3DDeviceImpl_GetRenderTargetData,
8080 IWineD3DDeviceImpl_GetFrontBufferData,
8081 /*** Internal use IWineD3DDevice methods ***/
8082 IWineD3DDeviceImpl_SetupTextureStates,
8083 /*** object tracking ***/
8084 IWineD3DDeviceImpl_ResourceReleased
8088 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8089 WINED3DRS_ALPHABLENDENABLE ,
8090 WINED3DRS_ALPHAFUNC ,
8091 WINED3DRS_ALPHAREF ,
8092 WINED3DRS_ALPHATESTENABLE ,
8093 WINED3DRS_BLENDOP ,
8094 WINED3DRS_COLORWRITEENABLE ,
8095 WINED3DRS_DESTBLEND ,
8096 WINED3DRS_DITHERENABLE ,
8097 WINED3DRS_FILLMODE ,
8098 WINED3DRS_FOGDENSITY ,
8099 WINED3DRS_FOGEND ,
8100 WINED3DRS_FOGSTART ,
8101 WINED3DRS_LASTPIXEL ,
8102 WINED3DRS_SHADEMODE ,
8103 WINED3DRS_SRCBLEND ,
8104 WINED3DRS_STENCILENABLE ,
8105 WINED3DRS_STENCILFAIL ,
8106 WINED3DRS_STENCILFUNC ,
8107 WINED3DRS_STENCILMASK ,
8108 WINED3DRS_STENCILPASS ,
8109 WINED3DRS_STENCILREF ,
8110 WINED3DRS_STENCILWRITEMASK ,
8111 WINED3DRS_STENCILZFAIL ,
8112 WINED3DRS_TEXTUREFACTOR ,
8113 WINED3DRS_WRAP0 ,
8114 WINED3DRS_WRAP1 ,
8115 WINED3DRS_WRAP2 ,
8116 WINED3DRS_WRAP3 ,
8117 WINED3DRS_WRAP4 ,
8118 WINED3DRS_WRAP5 ,
8119 WINED3DRS_WRAP6 ,
8120 WINED3DRS_WRAP7 ,
8121 WINED3DRS_ZENABLE ,
8122 WINED3DRS_ZFUNC ,
8123 WINED3DRS_ZWRITEENABLE
8126 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8127 WINED3DTSS_ADDRESSW ,
8128 WINED3DTSS_ALPHAARG0 ,
8129 WINED3DTSS_ALPHAARG1 ,
8130 WINED3DTSS_ALPHAARG2 ,
8131 WINED3DTSS_ALPHAOP ,
8132 WINED3DTSS_BUMPENVLOFFSET ,
8133 WINED3DTSS_BUMPENVLSCALE ,
8134 WINED3DTSS_BUMPENVMAT00 ,
8135 WINED3DTSS_BUMPENVMAT01 ,
8136 WINED3DTSS_BUMPENVMAT10 ,
8137 WINED3DTSS_BUMPENVMAT11 ,
8138 WINED3DTSS_COLORARG0 ,
8139 WINED3DTSS_COLORARG1 ,
8140 WINED3DTSS_COLORARG2 ,
8141 WINED3DTSS_COLOROP ,
8142 WINED3DTSS_RESULTARG ,
8143 WINED3DTSS_TEXCOORDINDEX ,
8144 WINED3DTSS_TEXTURETRANSFORMFLAGS
8147 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8148 WINED3DSAMP_ADDRESSU ,
8149 WINED3DSAMP_ADDRESSV ,
8150 WINED3DSAMP_ADDRESSW ,
8151 WINED3DSAMP_BORDERCOLOR ,
8152 WINED3DSAMP_MAGFILTER ,
8153 WINED3DSAMP_MINFILTER ,
8154 WINED3DSAMP_MIPFILTER ,
8155 WINED3DSAMP_MIPMAPLODBIAS ,
8156 WINED3DSAMP_MAXMIPLEVEL ,
8157 WINED3DSAMP_MAXANISOTROPY ,
8158 WINED3DSAMP_SRGBTEXTURE ,
8159 WINED3DSAMP_ELEMENTINDEX
8162 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8163 WINED3DRS_AMBIENT ,
8164 WINED3DRS_AMBIENTMATERIALSOURCE ,
8165 WINED3DRS_CLIPPING ,
8166 WINED3DRS_CLIPPLANEENABLE ,
8167 WINED3DRS_COLORVERTEX ,
8168 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8169 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8170 WINED3DRS_FOGDENSITY ,
8171 WINED3DRS_FOGEND ,
8172 WINED3DRS_FOGSTART ,
8173 WINED3DRS_FOGTABLEMODE ,
8174 WINED3DRS_FOGVERTEXMODE ,
8175 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8176 WINED3DRS_LIGHTING ,
8177 WINED3DRS_LOCALVIEWER ,
8178 WINED3DRS_MULTISAMPLEANTIALIAS ,
8179 WINED3DRS_MULTISAMPLEMASK ,
8180 WINED3DRS_NORMALIZENORMALS ,
8181 WINED3DRS_PATCHEDGESTYLE ,
8182 WINED3DRS_POINTSCALE_A ,
8183 WINED3DRS_POINTSCALE_B ,
8184 WINED3DRS_POINTSCALE_C ,
8185 WINED3DRS_POINTSCALEENABLE ,
8186 WINED3DRS_POINTSIZE ,
8187 WINED3DRS_POINTSIZE_MAX ,
8188 WINED3DRS_POINTSIZE_MIN ,
8189 WINED3DRS_POINTSPRITEENABLE ,
8190 WINED3DRS_RANGEFOGENABLE ,
8191 WINED3DRS_SPECULARMATERIALSOURCE ,
8192 WINED3DRS_TWEENFACTOR ,
8193 WINED3DRS_VERTEXBLEND
8196 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8197 WINED3DTSS_TEXCOORDINDEX ,
8198 WINED3DTSS_TEXTURETRANSFORMFLAGS
8201 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8202 WINED3DSAMP_DMAPOFFSET