Include new tests.
[wine/multimedia.git] / dlls / ddraw / d3ddevice / mesa.c
blob159187218c9832deb30e437a57e9f6cbaeee823c
1 /* Direct3D Device
2 * Copyright (c) 1998-2004 Lionel ULMER
3 * Copyright (c) 2002-2004 Christian Costa
5 * This file contains the MESA implementation of all the D3D devices that
6 * Wine supports.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <math.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winerror.h"
35 #include "objbase.h"
36 #include "wingdi.h"
37 #include "ddraw.h"
38 #include "d3d.h"
39 #include "wine/debug.h"
40 #include "wine/library.h"
42 #include "mesa_private.h"
43 #include "main.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
46 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
48 /* x11drv GDI escapes */
49 #define X11DRV_ESCAPE 6789
50 enum x11drv_escape_codes
52 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
53 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
54 X11DRV_GET_FONT, /* get current X font for a DC */
57 /* They are non-static as they are used by Direct3D in the creation function */
58 const GUID IID_D3DDEVICE_OpenGL = {
59 0x31416d44,
60 0x86ae,
61 0x11d2,
62 { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
65 const float id_mat[16] = {
66 1.0, 0.0, 0.0, 0.0,
67 0.0, 1.0, 0.0, 0.0,
68 0.0, 0.0, 1.0, 0.0,
69 0.0, 0.0, 0.0, 1.0
72 /* This is filled at DLL loading time */
73 static D3DDEVICEDESC7 opengl_device_caps;
74 GL_EXTENSIONS_LIST GL_extensions;
76 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
77 D3DPRIMITIVETYPE d3dptPrimitiveType,
78 DWORD d3dvtVertexType,
79 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
80 DWORD dwVertexCount,
81 LPWORD dwIndices,
82 DWORD dwIndexCount,
83 DWORD dwFlags) ;
85 static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
87 /* retrieve the X display to use on a given DC */
88 inline static Display *get_display( HDC hdc )
90 Display *display;
91 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
93 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
94 sizeof(display), (LPSTR)&display )) display = NULL;
96 return display;
99 #define UNLOCK_TEX_SIZE 256
101 #define DEPTH_RANGE_BIT (0x00000001 << 0)
102 #define VIEWPORT_BIT (0x00000001 << 1)
104 static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
105 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
106 DWORD opt_bitmap = 0x00000000;
108 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
109 ((d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE))) {
110 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
111 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
112 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
114 /* Disable multi-texturing for level 1 to disable all others */
115 glDisable(GL_TEXTURE_2D);
117 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
118 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
119 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
121 if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
122 (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
123 glEnable(GL_TEXTURE_2D);
124 if (gl_d3d_dev->unlock_tex == 0) {
125 glGenTextures(1, &gl_d3d_dev->unlock_tex);
126 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
127 *initial = TRUE;
128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
132 } else {
133 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
134 *initial = FALSE;
136 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
137 glMatrixMode(GL_TEXTURE);
138 glLoadIdentity();
141 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
142 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
143 d3ddevice_set_ortho(d3d_dev);
146 if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
147 glEnable(GL_SCISSOR_TEST);
148 if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
149 (d3d_dev->active_viewport.dvMaxZ != 1.0)) {
150 glDepthRange(0.0, 1.0);
151 opt_bitmap |= DEPTH_RANGE_BIT;
153 if ((d3d_dev->active_viewport.dwX != 0) ||
154 (d3d_dev->active_viewport.dwY != 0) ||
155 (d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
156 (d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
157 glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
158 opt_bitmap |= VIEWPORT_BIT;
160 glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
161 pRect->right - pRect->left, pRect->bottom - pRect->top);
162 if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
163 if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
164 if (use_alpha) {
165 if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
166 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
167 glAlphaFunc(GL_NOTEQUAL, 0.0);
168 } else {
169 if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
171 if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
172 if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
173 if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
174 if (gl_d3d_dev->current_tex_env != GL_REPLACE)
175 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
177 return opt_bitmap;
180 static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
181 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
183 /* And restore all the various states modified by this code */
184 if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
185 if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
186 if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
187 glEnable(GL_ALPHA_TEST);
188 else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
189 glDisable(GL_ALPHA_TEST);
190 if (use_alpha) {
191 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
192 glAlphaFunc(gl_d3d_dev->current_alpha_test_func, gl_d3d_dev->current_alpha_test_ref);
194 if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
195 if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
196 if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
197 if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
198 glDisable(GL_SCISSOR_TEST);
199 if (opt_bitmap & DEPTH_RANGE_BIT) {
200 glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
202 if (opt_bitmap & VIEWPORT_BIT) {
203 glViewport(d3d_dev->active_viewport.dwX,
204 d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
205 d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
207 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
208 d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
211 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
212 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
213 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
215 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
216 /* Note that here we could directly re-bind the previous texture... But it would in some case be a spurious
217 bind if ever the game changes the texture just after.
219 So choose 0x00000001 to postpone the binding to the next time we draw something on screen. */
220 gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
221 if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
223 /* And re-enabled if needed texture level 1 */
224 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
225 (d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
226 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
227 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
228 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
230 glEnable(GL_TEXTURE_2D);
234 /* retrieve the X drawable to use on a given DC */
235 inline static Drawable get_drawable( HDC hdc )
237 Drawable drawable;
238 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
240 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
241 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
243 return drawable;
246 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
248 IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
249 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
251 TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
252 ENTER_GL();
253 if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
254 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_BACK]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK]);
256 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
257 gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
258 glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
259 LEAVE_GL();
261 return TRUE;
265 /*******************************************************************************
266 * OpenGL static functions
268 static void set_context(IDirect3DDeviceImpl* This)
270 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
272 TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
273 ENTER_GL();
274 if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
275 ERR("Error in setting current context (context %p drawable %ld)!\n",
276 glThis->gl_context, glThis->drawable);
278 LEAVE_GL();
281 static void fill_opengl_caps(D3DDEVICEDESC *d1)
283 d1->dwSize = sizeof(*d1);
284 d1->dwFlags = D3DDD_COLORMODEL | D3DDD_DEVCAPS | D3DDD_TRANSFORMCAPS | D3DDD_BCLIPPING | D3DDD_LIGHTINGCAPS |
285 D3DDD_LINECAPS | D3DDD_TRICAPS | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH |
286 D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT;
287 d1->dcmColorModel = D3DCOLOR_RGB;
288 d1->dwDevCaps = opengl_device_caps.dwDevCaps;
289 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
290 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
291 d1->bClipping = TRUE;
292 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
293 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
294 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
295 d1->dlcLightingCaps.dwNumLights = opengl_device_caps.dwMaxActiveLights;
296 d1->dpcLineCaps = opengl_device_caps.dpcLineCaps;
297 d1->dpcTriCaps = opengl_device_caps.dpcTriCaps;
298 d1->dwDeviceRenderBitDepth = opengl_device_caps.dwDeviceRenderBitDepth;
299 d1->dwDeviceZBufferBitDepth = opengl_device_caps.dwDeviceZBufferBitDepth;
300 d1->dwMaxBufferSize = 0;
301 d1->dwMaxVertexCount = 65536;
302 d1->dwMinTextureWidth = opengl_device_caps.dwMinTextureWidth;
303 d1->dwMinTextureHeight = opengl_device_caps.dwMinTextureHeight;
304 d1->dwMaxTextureWidth = opengl_device_caps.dwMaxTextureWidth;
305 d1->dwMaxTextureHeight = opengl_device_caps.dwMaxTextureHeight;
306 d1->dwMinStippleWidth = 1;
307 d1->dwMinStippleHeight = 1;
308 d1->dwMaxStippleWidth = 32;
309 d1->dwMaxStippleHeight = 32;
310 d1->dwMaxTextureRepeat = opengl_device_caps.dwMaxTextureRepeat;
311 d1->dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureAspectRatio;
312 d1->dwMaxAnisotropy = opengl_device_caps.dwMaxAnisotropy;
313 d1->dvGuardBandLeft = opengl_device_caps.dvGuardBandLeft;
314 d1->dvGuardBandRight = opengl_device_caps.dvGuardBandRight;
315 d1->dvGuardBandTop = opengl_device_caps.dvGuardBandTop;
316 d1->dvGuardBandBottom = opengl_device_caps.dvGuardBandBottom;
317 d1->dvExtentsAdjust = opengl_device_caps.dvExtentsAdjust;
318 d1->dwStencilCaps = opengl_device_caps.dwStencilCaps;
319 d1->dwFVFCaps = opengl_device_caps.dwFVFCaps;
320 d1->dwTextureOpCaps = opengl_device_caps.dwTextureOpCaps;
321 d1->wMaxTextureBlendStages = opengl_device_caps.wMaxTextureBlendStages;
322 d1->wMaxSimultaneousTextures = opengl_device_caps.wMaxSimultaneousTextures;
325 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
327 *d = opengl_device_caps;
330 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
332 D3DDEVICEDESC dref, d1, d2;
333 HRESULT ret_value;
335 /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
336 Let's put the string in a sufficiently sized array in writable memory. */
337 char device_name[50];
338 strcpy(device_name,"direct3d");
340 fill_opengl_caps(&dref);
342 if (version > 1) {
343 /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
344 char interface_name[] = "WINE Reference Direct3DX using OpenGL";
345 TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
346 d1 = dref;
347 d2 = dref;
348 ret_value = cb((LPIID) &IID_IDirect3DRefDevice, interface_name, device_name, &d1, &d2, context);
349 if (ret_value != D3DENUMRET_OK)
350 return ret_value;
354 char interface_name[] = "WINE Direct3DX using OpenGL";
355 TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
356 d1 = dref;
357 d2 = dref;
358 ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, interface_name, device_name, &d1, &d2, context);
359 if (ret_value != D3DENUMRET_OK)
360 return ret_value;
363 return D3DENUMRET_OK;
366 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
368 D3DDEVICEDESC7 ddesc;
369 char interface_name[] = "WINE Direct3D7 using OpenGL";
370 char device_name[] = "Wine D3D7 device";
372 fill_opengl_caps_7(&ddesc);
374 TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
376 return cb(interface_name, device_name, &ddesc, context);
379 ULONG WINAPI
380 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
382 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
383 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
384 ULONG ref = InterlockedDecrement(&This->ref);
386 TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, ref + 1);
388 if (!ref) {
389 int i;
390 IDirectDrawSurfaceImpl *surface = This->surface, *surf;
392 /* Release texture associated with the device */
393 for (i = 0; i < MAX_TEXTURES; i++) {
394 if (This->current_texture[i] != NULL)
395 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
396 HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
399 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
400 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
401 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
402 surf->aux_ctx = NULL;
403 surf->aux_data = NULL;
404 surf->aux_flip = NULL;
405 break;
408 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
409 IDirectDrawSurfaceImpl *surf2;
410 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
411 for (; surf2 != NULL; surf2 = surf2->next_attached) {
412 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
413 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
414 /* Override the Lock / Unlock function for all these surfaces */
415 surf2->lock_update = surf2->lock_update_prev;
416 surf2->unlock_update = surf2->unlock_update_prev;
417 /* And install also the blt / bltfast overrides */
418 surf2->aux_blt = NULL;
419 surf2->aux_bltfast = NULL;
421 surf2->d3ddevice = NULL;
425 /* And warn the D3D object that this device is no longer active... */
426 This->d3d->d3d_removed_device(This->d3d, This);
428 HeapFree(GetProcessHeap(), 0, This->world_mat);
429 HeapFree(GetProcessHeap(), 0, This->view_mat);
430 HeapFree(GetProcessHeap(), 0, This->proj_mat);
432 if (glThis->surface_ptr)
433 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
435 DeleteCriticalSection(&(This->crit));
437 ENTER_GL();
438 if (glThis->unlock_tex)
439 glDeleteTextures(1, &(glThis->unlock_tex));
440 glXDestroyContext(glThis->display, glThis->gl_context);
441 LEAVE_GL();
442 HeapFree(GetProcessHeap(), 0, This->clipping_planes);
444 HeapFree(GetProcessHeap(), 0, This);
445 return 0;
447 return ref;
450 HRESULT WINAPI
451 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
452 LPD3DDEVICEDESC lpD3DHWDevDesc,
453 LPD3DDEVICEDESC lpD3DHELDevDesc)
455 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
456 D3DDEVICEDESC desc;
457 DWORD dwSize;
459 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
461 fill_opengl_caps(&desc);
462 dwSize = lpD3DHWDevDesc->dwSize;
463 memset(lpD3DHWDevDesc, 0, dwSize);
464 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
466 dwSize = lpD3DHELDevDesc->dwSize;
467 memset(lpD3DHELDevDesc, 0, dwSize);
468 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
470 TRACE(" returning caps : (no dump function yet)\n");
472 return DD_OK;
475 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
476 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
477 LPVOID context)
479 DDSURFACEDESC sdesc;
480 LPDDPIXELFORMAT pformat;
482 /* Do the texture enumeration */
483 sdesc.dwSize = sizeof(DDSURFACEDESC);
484 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
485 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
486 pformat = &(sdesc.ddpfPixelFormat);
487 pformat->dwSize = sizeof(DDPIXELFORMAT);
488 pformat->dwFourCC = 0;
490 TRACE("Enumerating GL_RGBA unpacked (32)\n");
491 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
492 pformat->u1.dwRGBBitCount = 32;
493 pformat->u2.dwRBitMask = 0x00FF0000;
494 pformat->u3.dwGBitMask = 0x0000FF00;
495 pformat->u4.dwBBitMask = 0x000000FF;
496 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
497 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
498 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
500 TRACE("Enumerating GL_RGB unpacked (32)\n");
501 pformat->dwFlags = DDPF_RGB;
502 pformat->u1.dwRGBBitCount = 32;
503 pformat->u2.dwRBitMask = 0x00FF0000;
504 pformat->u3.dwGBitMask = 0x0000FF00;
505 pformat->u4.dwBBitMask = 0x000000FF;
506 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
507 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
508 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
510 TRACE("Enumerating GL_RGB unpacked (24)\n");
511 pformat->dwFlags = DDPF_RGB;
512 pformat->u1.dwRGBBitCount = 24;
513 pformat->u2.dwRBitMask = 0x00FF0000;
514 pformat->u3.dwGBitMask = 0x0000FF00;
515 pformat->u4.dwBBitMask = 0x000000FF;
516 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
517 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
518 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
520 /* Note : even if this is an 'emulated' texture format, it needs to be first
521 as some dumb applications seem to rely on that. */
522 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
523 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
524 pformat->u1.dwRGBBitCount = 16;
525 pformat->u2.dwRBitMask = 0x00007C00;
526 pformat->u3.dwGBitMask = 0x000003E0;
527 pformat->u4.dwBBitMask = 0x0000001F;
528 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
529 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
530 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
532 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
533 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
534 pformat->u1.dwRGBBitCount = 16;
535 pformat->u2.dwRBitMask = 0x00000F00;
536 pformat->u3.dwGBitMask = 0x000000F0;
537 pformat->u4.dwBBitMask = 0x0000000F;
538 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
539 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
540 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
542 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
543 pformat->dwFlags = DDPF_RGB;
544 pformat->u1.dwRGBBitCount = 16;
545 pformat->u2.dwRBitMask = 0x0000F800;
546 pformat->u3.dwGBitMask = 0x000007E0;
547 pformat->u4.dwBBitMask = 0x0000001F;
548 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
549 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
550 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
552 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
553 pformat->dwFlags = DDPF_RGB;
554 pformat->u1.dwRGBBitCount = 16;
555 pformat->u2.dwRBitMask = 0x00007C00;
556 pformat->u3.dwGBitMask = 0x000003E0;
557 pformat->u4.dwBBitMask = 0x0000001F;
558 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
559 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
560 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
562 #if 0
563 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
564 find enumerated, others the last one. And both want to have the ARGB one.
566 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
568 /* See argument about the RGBA format for 'packed' texture formats */
569 TRACE("Enumerating GL_RGBA unpacked (32)\n");
570 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
571 pformat->u1.dwRGBBitCount = 32;
572 pformat->u2.dwRBitMask = 0xFF000000;
573 pformat->u3.dwGBitMask = 0x00FF0000;
574 pformat->u4.dwBBitMask = 0x0000FF00;
575 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
576 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
577 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
579 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
580 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
581 pformat->u1.dwRGBBitCount = 16;
582 pformat->u2.dwRBitMask = 0x0000F000;
583 pformat->u3.dwGBitMask = 0x00000F00;
584 pformat->u4.dwBBitMask = 0x000000F0;
585 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
586 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
587 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
589 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
590 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
591 pformat->u1.dwRGBBitCount = 16;
592 pformat->u2.dwRBitMask = 0x0000F800;
593 pformat->u3.dwGBitMask = 0x000007C0;
594 pformat->u4.dwBBitMask = 0x0000003E;
595 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
596 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
597 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
598 #endif
600 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
601 pformat->dwFlags = DDPF_RGB;
602 pformat->u1.dwRGBBitCount = 8;
603 pformat->u2.dwRBitMask = 0x000000E0;
604 pformat->u3.dwGBitMask = 0x0000001C;
605 pformat->u4.dwBBitMask = 0x00000003;
606 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
607 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
608 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
610 TRACE("Enumerating Paletted (8)\n");
611 pformat->dwFlags = DDPF_PALETTEINDEXED8;
612 pformat->u1.dwRGBBitCount = 8;
613 pformat->u2.dwRBitMask = 0x00000000;
614 pformat->u3.dwGBitMask = 0x00000000;
615 pformat->u4.dwBBitMask = 0x00000000;
616 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
617 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
618 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
620 if (GL_extensions.s3tc_compressed_texture) {
621 TRACE("Enumerating DXT1\n");
622 pformat->dwFlags = DDPF_FOURCC;
623 pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
624 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
625 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
627 TRACE("Enumerating DXT3\n");
628 pformat->dwFlags = DDPF_FOURCC;
629 pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
630 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
631 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
633 TRACE("Enumerating DXT5\n");
634 pformat->dwFlags = DDPF_FOURCC;
635 pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
636 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
637 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
640 TRACE("End of enumeration\n");
641 return DD_OK;
645 HRESULT
646 d3ddevice_find(IDirectDrawImpl *d3d,
647 LPD3DFINDDEVICESEARCH lpD3DDFS,
648 LPD3DFINDDEVICERESULT lplpD3DDevice)
650 D3DDEVICEDESC desc;
652 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
653 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
654 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
655 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
657 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
658 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
659 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
660 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
661 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
662 TRACE(" no match for this GUID.\n");
663 return DDERR_INVALIDPARAMS;
667 /* Now return our own GUID */
668 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
669 fill_opengl_caps(&desc);
670 lplpD3DDevice->ddHwDesc = desc;
671 lplpD3DDevice->ddSwDesc = desc;
673 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
675 return D3D_OK;
678 HRESULT WINAPI
679 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
680 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
681 LPVOID lpArg)
683 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
684 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
685 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg);
688 HRESULT WINAPI
689 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
690 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
691 LPVOID lpArg)
693 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
694 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
695 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg);
698 HRESULT WINAPI
699 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
700 D3DRENDERSTATETYPE dwRenderStateType,
701 DWORD dwRenderState)
703 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
704 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
706 /* Call the render state functions */
707 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
708 set_render_state(This, dwRenderStateType, &This->state_block);
710 return DD_OK;
713 HRESULT WINAPI
714 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
715 D3DRENDERSTATETYPE dwRenderStateType,
716 LPDWORD lpdwRenderState)
718 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
719 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
721 /* Call the render state functions */
722 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
724 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
726 return DD_OK;
729 HRESULT WINAPI
730 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
731 D3DLIGHTSTATETYPE dwLightStateType,
732 LPDWORD lpdwLightState)
734 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
736 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
738 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
739 TRACE("Unexpected Light State Type\n");
740 return DDERR_INVALIDPARAMS;
743 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
744 *lpdwLightState = This->material;
745 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
746 *lpdwLightState = D3DCOLOR_RGB;
747 } else {
748 D3DRENDERSTATETYPE rs;
749 switch (dwLightStateType) {
750 case D3DLIGHTSTATE_AMBIENT: /* 2 */
751 rs = D3DRENDERSTATE_AMBIENT;
752 break;
753 case D3DLIGHTSTATE_FOGMODE: /* 4 */
754 rs = D3DRENDERSTATE_FOGVERTEXMODE;
755 break;
756 case D3DLIGHTSTATE_FOGSTART: /* 5 */
757 rs = D3DRENDERSTATE_FOGSTART;
758 break;
759 case D3DLIGHTSTATE_FOGEND: /* 6 */
760 rs = D3DRENDERSTATE_FOGEND;
761 break;
762 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
763 rs = D3DRENDERSTATE_FOGDENSITY;
764 break;
765 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
766 rs = D3DRENDERSTATE_COLORVERTEX;
767 break;
768 default:
769 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
770 return DDERR_INVALIDPARAMS;
773 IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
774 rs,lpdwLightState);
777 return DD_OK;
780 HRESULT WINAPI
781 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
782 D3DLIGHTSTATETYPE dwLightStateType,
783 DWORD dwLightState)
785 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
787 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
789 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
790 TRACE("Unexpected Light State Type\n");
791 return DDERR_INVALIDPARAMS;
794 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
795 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
797 if (mat != NULL) {
798 TRACE(" activating material %p.\n", mat);
799 mat->activate(mat);
800 } else {
801 FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
803 This->material = dwLightState;
804 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
805 switch (dwLightState) {
806 case D3DCOLOR_MONO:
807 ERR("DDCOLOR_MONO should not happen!\n");
808 break;
809 case D3DCOLOR_RGB:
810 /* We are already in this mode */
811 TRACE("Setting color model to RGB (no-op).\n");
812 break;
813 default:
814 ERR("Unknown color model!\n");
815 return DDERR_INVALIDPARAMS;
817 } else {
818 D3DRENDERSTATETYPE rs;
819 switch (dwLightStateType) {
820 case D3DLIGHTSTATE_AMBIENT: /* 2 */
821 rs = D3DRENDERSTATE_AMBIENT;
822 break;
823 case D3DLIGHTSTATE_FOGMODE: /* 4 */
824 rs = D3DRENDERSTATE_FOGVERTEXMODE;
825 break;
826 case D3DLIGHTSTATE_FOGSTART: /* 5 */
827 rs = D3DRENDERSTATE_FOGSTART;
828 break;
829 case D3DLIGHTSTATE_FOGEND: /* 6 */
830 rs = D3DRENDERSTATE_FOGEND;
831 break;
832 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
833 rs = D3DRENDERSTATE_FOGDENSITY;
834 break;
835 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
836 rs = D3DRENDERSTATE_COLORVERTEX;
837 break;
838 default:
839 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
840 return DDERR_INVALIDPARAMS;
843 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
844 rs,dwLightState);
847 return DD_OK;
850 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
852 switch (d3dpt) {
853 case D3DPT_POINTLIST:
854 TRACE(" primitive type is POINTS\n");
855 return GL_POINTS;
857 case D3DPT_LINELIST:
858 TRACE(" primitive type is LINES\n");
859 return GL_LINES;
861 case D3DPT_LINESTRIP:
862 TRACE(" primitive type is LINE_STRIP\n");
863 return GL_LINE_STRIP;
865 case D3DPT_TRIANGLELIST:
866 TRACE(" primitive type is TRIANGLES\n");
867 return GL_TRIANGLES;
869 case D3DPT_TRIANGLESTRIP:
870 TRACE(" primitive type is TRIANGLE_STRIP\n");
871 return GL_TRIANGLE_STRIP;
873 case D3DPT_TRIANGLEFAN:
874 TRACE(" primitive type is TRIANGLE_FAN\n");
875 return GL_TRIANGLE_FAN;
877 default:
878 FIXME("Unhandled primitive %08x\n", d3dpt);
879 return GL_POINTS;
883 /* This function calculate the Z coordinate from Zproj */
884 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
886 float a,b,c,d;
887 /* Assume that X = Y = 0 and W = 1 */
888 a = This->proj_mat->_33;
889 b = This->proj_mat->_34;
890 c = This->proj_mat->_43;
891 d = This->proj_mat->_44;
892 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
893 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
894 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
896 return (d*Zproj - c) / (a - b*Zproj);
899 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
900 int i;
902 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
904 for (i = 0; i < 3; i++) {
905 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
906 DWORD elt;
907 for (elt = 0; elt < 0x10000; elt++) {
908 /* We apply the fog transformation and cache the result */
909 DWORD fog_intensity = elt & 0xFF;
910 DWORD vertex_color = (elt >> 8) & 0xFF;
911 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
916 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
917 BOOLEAN vertex_transformed,
918 BOOLEAN vertex_lit) {
919 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
921 /* Puts GL in the correct lighting / transformation mode */
922 if ((vertex_transformed == FALSE) &&
923 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
924 /* Need to put the correct transformation again if we go from Transformed
925 vertices to non-transformed ones.
927 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
928 This->world_mat, This->view_mat, This->proj_mat);
929 glThis->transform_state = GL_TRANSFORM_NORMAL;
931 } else if (vertex_transformed &&
932 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
933 /* Set our orthographic projection */
934 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
935 glThis->transform_state = GL_TRANSFORM_ORTHO;
936 d3ddevice_set_ortho(This);
940 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
941 if no fogging state change occurred */
942 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
943 if (vertex_transformed) {
944 if (glThis->fogging != 0) {
945 glDisable(GL_FOG);
946 glThis->fogging = 0;
948 /* Now check if our fog_table still corresponds to the current vertex color.
949 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
950 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
951 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
952 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
953 /* We need to rebuild our fog table.... */
954 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
956 } else {
957 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
958 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
959 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
960 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
961 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
963 if (vertex_lit == FALSE) {
964 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
965 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
966 } else {
967 /* Special case of 'pixel fog' */
968 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
969 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
971 if (glThis->fogging == 0) {
972 glEnable(GL_FOG);
973 glThis->fogging = 1;
975 } else {
976 if (glThis->fogging != 0) {
977 glDisable(GL_FOG);
978 glThis->fogging = 0;
982 } else {
983 if (glThis->fogging != 0) {
984 glDisable(GL_FOG);
985 glThis->fogging = 0;
989 /* Handle the 'no-normal' case */
990 if ((vertex_lit == FALSE) && This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1]) {
991 if (glThis->lighting == 0) {
992 glEnable(GL_LIGHTING);
993 glThis->lighting = 1;
995 } else {
996 if (glThis->lighting != 0) {
997 glDisable(GL_LIGHTING);
998 glThis->lighting = 0;
1002 /* Handle the code for pre-vertex material properties */
1003 if (vertex_transformed == FALSE) {
1004 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1005 This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1006 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1007 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1008 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1009 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1010 glEnable(GL_COLOR_MATERIAL);
1017 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1018 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1020 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1022 switch (d3dvt) {
1023 case D3DVT_VERTEX: {
1024 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1025 strided.position.dwStride = sizeof(D3DVERTEX);
1026 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1027 strided.normal.dwStride = sizeof(D3DVERTEX);
1028 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1029 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1030 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1031 } break;
1033 case D3DVT_LVERTEX: {
1034 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1035 strided.position.dwStride = sizeof(D3DLVERTEX);
1036 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1037 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1038 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1039 strided.specular.dwStride = sizeof(D3DLVERTEX);
1040 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1041 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1042 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1043 } break;
1045 case D3DVT_TLVERTEX: {
1046 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1047 strided.position.dwStride = sizeof(D3DTLVERTEX);
1048 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1049 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1050 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1051 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1052 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1053 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1054 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1055 } break;
1057 default:
1058 FIXME("Unhandled vertex type %08x\n", d3dvt);
1059 break;
1063 HRESULT WINAPI
1064 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1065 D3DPRIMITIVETYPE d3dptPrimitiveType,
1066 D3DVERTEXTYPE d3dvtVertexType,
1067 LPVOID lpvVertices,
1068 DWORD dwVertexCount,
1069 DWORD dwFlags)
1071 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1073 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1074 if (TRACE_ON(ddraw)) {
1075 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1078 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1080 return DD_OK;
1083 HRESULT WINAPI
1084 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1085 D3DPRIMITIVETYPE d3dptPrimitiveType,
1086 D3DVERTEXTYPE d3dvtVertexType,
1087 LPVOID lpvVertices,
1088 DWORD dwVertexCount,
1089 LPWORD dwIndices,
1090 DWORD dwIndexCount,
1091 DWORD dwFlags)
1093 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1094 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1095 if (TRACE_ON(ddraw)) {
1096 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1099 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1101 return DD_OK;
1104 HRESULT WINAPI
1105 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1106 LPD3DEXECUTEBUFFERDESC lpDesc,
1107 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1108 IUnknown* pUnkOuter)
1110 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1111 IDirect3DExecuteBufferImpl *ret;
1112 HRESULT ret_value;
1114 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1116 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1117 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1119 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1121 return ret_value;
1124 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1125 static BOOLEAN first = TRUE;
1126 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1127 unsigned int row;
1128 GLenum type;
1130 if (first) {
1131 MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1132 first = FALSE;
1135 TRACE("flushing ZBuffer back to GL\n");
1137 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1138 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1139 d3ddevice_set_ortho(d3d_dev);
1142 glMatrixMode(GL_MODELVIEW);
1143 glLoadIdentity();
1145 if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1146 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1147 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1149 /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1150 in some drivers...
1152 switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1153 case 16: type = GL_UNSIGNED_SHORT; break;
1154 case 32: type = GL_UNSIGNED_INT; break;
1155 default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1158 for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1159 /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1160 glRasterPos2i(0, row + 1);
1161 glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1162 ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1165 restore_state:
1166 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1167 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1168 glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1169 if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1172 /* These are the various handler used in the generic path */
1173 inline static void handle_xyz(D3DVALUE *coords) {
1174 glVertex3fv(coords);
1176 inline static void handle_xyzrhw(D3DVALUE *coords) {
1177 if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1178 glVertex3fv(coords);
1179 else {
1180 GLfloat w = 1.0 / coords[3];
1182 glVertex4f(coords[0] * w,
1183 coords[1] * w,
1184 coords[2] * w,
1188 inline static void handle_normal(D3DVALUE *coords) {
1189 glNormal3fv(coords);
1192 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1193 if (sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] ||
1194 sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1]) {
1195 glColor4ub((*color >> 16) & 0xFF,
1196 (*color >> 8) & 0xFF,
1197 (*color >> 0) & 0xFF,
1198 (*color >> 24) & 0xFF);
1199 } else {
1200 glColor3ub((*color >> 16) & 0xFF,
1201 (*color >> 8) & 0xFF,
1202 (*color >> 0) & 0xFF);
1206 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1207 glColor4ub((*color >> 16) & 0xFF,
1208 (*color >> 8) & 0xFF,
1209 (*color >> 0) & 0xFF,
1210 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1213 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1214 if ((lighted == FALSE) &&
1215 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1216 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1217 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1218 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1219 handle_diffuse_base(sb, color);
1221 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1222 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1223 handle_diffuse_base(sb, color);
1225 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1226 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1227 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1228 handle_diffuse_base(sb, color);
1230 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1231 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1232 handle_diffuse_base(sb, color);
1234 } else {
1235 handle_diffuse_base(sb, color);
1239 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1240 if ((lighted == FALSE) &&
1241 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1242 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1243 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1244 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1245 handle_specular_base(sb, color);
1247 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1248 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1249 handle_specular_base(sb, color);
1251 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1252 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1253 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1254 handle_specular_base(sb, color);
1256 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1257 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1258 handle_specular_base(sb, color);
1261 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1264 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1265 if (lighted) {
1266 DWORD color = *color_d;
1267 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
1268 /* Special case where the specular value is used to do fogging */
1269 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1270 color &= 0xFF000000; /* Only keep the alpha component */
1271 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1272 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1273 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1275 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1276 /* Standard specular value in transformed mode. TODO */
1278 handle_diffuse_base(sb, &color);
1279 } else {
1280 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1281 handle_diffuse(sb, color_d, FALSE);
1282 handle_specular(sb, color_s, FALSE);
1283 } else {
1284 /* In that case, only put the diffuse color... */
1285 handle_diffuse_base(sb, color_d);
1290 inline static void handle_texture(D3DVALUE *coords) {
1291 glTexCoord2fv(coords);
1293 inline static void handle_textures(const D3DVALUE *coords, int tex_stage) {
1294 if (GL_extensions.glMultiTexCoord2fv) {
1295 GL_extensions.glMultiTexCoord2fv(GL_TEXTURE0_WINE + tex_stage, coords);
1296 } else {
1297 if (tex_stage == 0) glTexCoord2fv(coords);
1301 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1302 D3DPRIMITIVETYPE d3dptPrimitiveType,
1303 DWORD d3dvtVertexType,
1304 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1305 DWORD dwVertexCount,
1306 LPWORD dwIndices,
1307 DWORD dwIndexCount,
1308 DWORD dwFlags)
1310 BOOLEAN vertex_lighted = FALSE;
1311 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1312 int num_active_stages = 0;
1313 int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
1315 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1316 if (TRACE_ON(ddraw)) {
1317 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1320 /* This is to prevent 'thread contention' between a thread locking the device and another
1321 doing 3D display on it... */
1322 EnterCriticalSection(&(This->crit));
1324 ENTER_GL();
1325 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1326 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1328 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1330 if (This->current_zbuffer == NULL) {
1331 /* Search for an attached ZBuffer */
1332 static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1333 LPDIRECTDRAWSURFACE7 zbuf;
1334 HRESULT hr;
1336 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1337 (DDSCAPS2 *) &zbuf_caps, &zbuf);
1338 if (!FAILED(hr)) {
1339 This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1340 IDirectDrawSurface7_Release(zbuf);
1343 if (This->current_zbuffer != NULL) {
1344 if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1345 flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1349 if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1350 ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1351 vertex_lighted = TRUE;
1353 /* Compute the number of active texture stages and set the various texture parameters */
1354 num_active_stages = draw_primitive_handle_textures(This);
1356 /* And restore to handle '0' in the case we use glTexCoord calls */
1357 if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1358 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1359 glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1362 draw_primitive_handle_GL_state(This,
1363 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1364 vertex_lighted);
1366 /* First, see if we can use the OpenGL vertex arrays... This is very limited
1367 for now to some 'special' cases where we can do a direct mapping between D3D
1368 types and GL types.
1370 Note: in the future all calls will go through vertex arrays but the arrays
1371 will be generated by this function.
1373 Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1374 (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1375 which, as we are little indian, gives a B, G, R, A storage in memory.
1377 if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1378 ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1379 int tex_stage;
1380 TRACE(" using GL vertex arrays for performance !\n");
1381 /* First, the vertices (we are sure we have some :-) */
1382 glEnableClientState(GL_VERTEX_ARRAY);
1383 glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1384 /* Then the normals */
1385 if (d3dvtVertexType & D3DFVF_NORMAL) {
1386 glEnableClientState(GL_NORMAL_ARRAY);
1387 glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1389 /* Then the diffuse colour */
1390 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1391 glEnableClientState(GL_COLOR_ARRAY);
1392 glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1393 ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1395 /* Then the various textures */
1396 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1397 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1398 if (tex_index >= num_tex_index) {
1399 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1400 tex_index = num_tex_index - 1;
1402 if (GL_extensions.glClientActiveTexture) {
1403 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1405 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1406 glTexCoordPointer(2, GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1407 lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1409 if (dwIndices != NULL) {
1410 glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1411 } else {
1412 glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1414 glDisableClientState(GL_VERTEX_ARRAY);
1415 if (d3dvtVertexType & D3DFVF_NORMAL) {
1416 glDisableClientState(GL_NORMAL_ARRAY);
1418 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1419 glDisableClientState(GL_COLOR_ARRAY);
1421 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1422 if (GL_extensions.glClientActiveTexture) {
1423 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1425 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1427 } else {
1428 glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1430 /* Some fast paths first before the generic case.... */
1431 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1432 unsigned int index;
1434 for (index = 0; index < dwIndexCount; index++) {
1435 int i = (dwIndices == NULL) ? index : dwIndices[index];
1436 D3DVALUE *normal =
1437 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1438 D3DVALUE *tex_coord =
1439 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1440 D3DVALUE *position =
1441 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1443 handle_normal(normal);
1444 handle_texture(tex_coord);
1445 handle_xyz(position);
1447 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1448 position[0], position[1], position[2],
1449 normal[0], normal[1], normal[2],
1450 tex_coord[0], tex_coord[1]);
1452 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1453 unsigned int index;
1455 for (index = 0; index < dwIndexCount; index++) {
1456 int i = (dwIndices == NULL) ? index : dwIndices[index];
1457 DWORD *color_d =
1458 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1459 DWORD *color_s =
1460 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1461 D3DVALUE *tex_coord =
1462 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1463 D3DVALUE *position =
1464 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1466 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1467 handle_texture(tex_coord);
1468 handle_xyzrhw(position);
1470 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1471 position[0], position[1], position[2], position[3],
1472 (*color_d >> 16) & 0xFF,
1473 (*color_d >> 8) & 0xFF,
1474 (*color_d >> 0) & 0xFF,
1475 (*color_d >> 24) & 0xFF,
1476 (*color_s >> 16) & 0xFF,
1477 (*color_s >> 8) & 0xFF,
1478 (*color_s >> 0) & 0xFF,
1479 (*color_s >> 24) & 0xFF,
1480 tex_coord[0], tex_coord[1]);
1482 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1483 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1484 /* This is the 'slow path' but that should support all possible vertex formats out there...
1485 Note that people should write a fast path for all vertex formats out there...
1487 unsigned int index;
1488 static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
1490 for (index = 0; index < dwIndexCount; index++) {
1491 int i = (dwIndices == NULL) ? index : dwIndices[index];
1492 int tex_stage;
1494 if (d3dvtVertexType & D3DFVF_NORMAL) {
1495 D3DVALUE *normal =
1496 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1497 handle_normal(normal);
1499 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1500 DWORD *color_d =
1501 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1502 DWORD *color_s =
1503 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1504 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1505 } else {
1506 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1507 DWORD *color_s =
1508 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1509 handle_specular(&(This->state_block), color_s, vertex_lighted);
1510 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1511 DWORD *color_d =
1512 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1513 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1517 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1518 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1519 if (tex_index >= num_tex_index) {
1520 handle_textures((const D3DVALUE *) no_index, tex_stage);
1521 } else {
1522 D3DVALUE *tex_coord =
1523 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1524 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1525 handle_textures(tex_coord, tex_stage);
1529 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1530 D3DVALUE *position =
1531 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1532 handle_xyz(position);
1533 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1534 D3DVALUE *position =
1535 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1536 handle_xyzrhw(position);
1539 if (TRACE_ON(ddraw_geom)) {
1540 unsigned int tex_index;
1542 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1543 D3DVALUE *position =
1544 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1545 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1546 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1547 D3DVALUE *position =
1548 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1549 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1551 if (d3dvtVertexType & D3DFVF_NORMAL) {
1552 D3DVALUE *normal =
1553 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1554 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1556 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1557 DWORD *color_d =
1558 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1559 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1560 (*color_d >> 16) & 0xFF,
1561 (*color_d >> 8) & 0xFF,
1562 (*color_d >> 0) & 0xFF,
1563 (*color_d >> 24) & 0xFF);
1565 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1566 DWORD *color_s =
1567 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1568 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1569 (*color_s >> 16) & 0xFF,
1570 (*color_s >> 8) & 0xFF,
1571 (*color_s >> 0) & 0xFF,
1572 (*color_s >> 24) & 0xFF);
1574 for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
1575 D3DVALUE *tex_coord =
1576 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1577 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1578 TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
1580 TRACE_(ddraw_geom)("\n");
1583 } else {
1584 ERR(" matrix weighting not handled yet....\n");
1587 glEnd();
1590 /* Whatever the case, disable the color material stuff */
1591 glDisable(GL_COLOR_MATERIAL);
1593 LEAVE_GL();
1594 TRACE("End\n");
1596 LeaveCriticalSection(&(This->crit));
1599 HRESULT WINAPI
1600 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1601 D3DPRIMITIVETYPE d3dptPrimitiveType,
1602 DWORD d3dvtVertexType,
1603 LPVOID lpvVertices,
1604 DWORD dwVertexCount,
1605 DWORD dwFlags)
1607 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1608 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1610 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1611 if (TRACE_ON(ddraw)) {
1612 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1615 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1616 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1618 return DD_OK;
1621 HRESULT WINAPI
1622 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1623 D3DPRIMITIVETYPE d3dptPrimitiveType,
1624 DWORD d3dvtVertexType,
1625 LPVOID lpvVertices,
1626 DWORD dwVertexCount,
1627 LPWORD dwIndices,
1628 DWORD dwIndexCount,
1629 DWORD dwFlags)
1631 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1632 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1634 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1635 if (TRACE_ON(ddraw)) {
1636 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1639 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1640 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1642 return DD_OK;
1645 HRESULT WINAPI
1646 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1647 D3DPRIMITIVETYPE d3dptPrimitiveType,
1648 DWORD dwVertexType,
1649 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1650 DWORD dwVertexCount,
1651 DWORD dwFlags)
1653 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1655 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1656 if (TRACE_ON(ddraw)) {
1657 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1659 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1661 return DD_OK;
1664 HRESULT WINAPI
1665 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1666 D3DPRIMITIVETYPE d3dptPrimitiveType,
1667 DWORD dwVertexType,
1668 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1669 DWORD dwVertexCount,
1670 LPWORD lpIndex,
1671 DWORD dwIndexCount,
1672 DWORD dwFlags)
1674 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1676 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1677 if (TRACE_ON(ddraw)) {
1678 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1681 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1683 return DD_OK;
1686 HRESULT WINAPI
1687 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1688 D3DPRIMITIVETYPE d3dptPrimitiveType,
1689 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1690 DWORD dwStartVertex,
1691 DWORD dwNumVertices,
1692 DWORD dwFlags)
1694 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1695 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1696 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1698 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1699 if (TRACE_ON(ddraw)) {
1700 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1703 if (vb_impl->processed) {
1704 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1705 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1707 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1708 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1709 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1711 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1712 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1714 } else {
1715 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1716 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1719 return DD_OK;
1722 HRESULT WINAPI
1723 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1724 D3DPRIMITIVETYPE d3dptPrimitiveType,
1725 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1726 DWORD dwStartVertex,
1727 DWORD dwNumVertices,
1728 LPWORD lpwIndices,
1729 DWORD dwIndexCount,
1730 DWORD dwFlags)
1732 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1733 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1734 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1736 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1737 if (TRACE_ON(ddraw)) {
1738 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1741 if (vb_impl->processed) {
1742 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1743 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1745 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1746 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1747 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1749 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1750 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1752 } else {
1753 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1754 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1757 return DD_OK;
1760 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1761 static BOOLEAN
1762 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1764 BOOLEAN is_complement = FALSE;
1765 BOOLEAN is_alpha_replicate = FALSE;
1766 BOOLEAN handled = TRUE;
1767 GLenum src;
1768 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1769 int num;
1771 if (is_color) {
1772 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1773 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1774 else {
1775 handled = FALSE;
1776 num = 0;
1778 if (tex_op == D3DTOP_SELECTARG2) {
1779 num = 1 - num;
1781 } else {
1782 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1783 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1784 else {
1785 handled = FALSE;
1786 num = 0;
1788 if (tex_op == D3DTOP_SELECTARG2) {
1789 num = 1 - num;
1793 if (dwState & D3DTA_COMPLEMENT) {
1794 is_complement = TRUE;
1796 if (dwState & D3DTA_ALPHAREPLICATE) {
1797 is_alpha_replicate = TRUE;
1799 dwState &= D3DTA_SELECTMASK;
1800 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1801 dwState = D3DTA_DIFFUSE;
1804 switch (dwState) {
1805 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1806 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1807 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1808 case D3DTA_TFACTOR: {
1809 /* Get the constant value from the current rendering state */
1810 GLfloat color[4];
1811 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1813 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1814 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1815 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1816 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1817 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1819 src = GL_CONSTANT_EXT;
1820 } break;
1821 default: src = GL_TEXTURE; handled = FALSE; break;
1824 if (is_color) {
1825 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1826 if (is_alpha_replicate) {
1827 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1828 } else {
1829 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1831 } else {
1832 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1833 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1836 return handled;
1839 HRESULT WINAPI
1840 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1841 DWORD dwStage,
1842 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1843 DWORD dwState)
1845 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1846 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1847 const char *type;
1848 DWORD prev_state;
1849 GLenum unit;
1851 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1853 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1854 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1855 return DD_OK;
1858 unit = GL_TEXTURE0_WINE + dwStage;
1859 if (unit != glThis->current_active_tex_unit) {
1860 GL_extensions.glActiveTexture(unit);
1861 glThis->current_active_tex_unit = unit;
1864 switch (d3dTexStageStateType) {
1865 #define GEN_CASE(a) case a: type = #a; break
1866 GEN_CASE(D3DTSS_COLOROP);
1867 GEN_CASE(D3DTSS_COLORARG1);
1868 GEN_CASE(D3DTSS_COLORARG2);
1869 GEN_CASE(D3DTSS_ALPHAOP);
1870 GEN_CASE(D3DTSS_ALPHAARG1);
1871 GEN_CASE(D3DTSS_ALPHAARG2);
1872 GEN_CASE(D3DTSS_BUMPENVMAT00);
1873 GEN_CASE(D3DTSS_BUMPENVMAT01);
1874 GEN_CASE(D3DTSS_BUMPENVMAT10);
1875 GEN_CASE(D3DTSS_BUMPENVMAT11);
1876 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1877 GEN_CASE(D3DTSS_ADDRESS);
1878 GEN_CASE(D3DTSS_ADDRESSU);
1879 GEN_CASE(D3DTSS_ADDRESSV);
1880 GEN_CASE(D3DTSS_BORDERCOLOR);
1881 GEN_CASE(D3DTSS_MAGFILTER);
1882 GEN_CASE(D3DTSS_MINFILTER);
1883 GEN_CASE(D3DTSS_MIPFILTER);
1884 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1885 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1886 GEN_CASE(D3DTSS_MAXANISOTROPY);
1887 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1888 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1889 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1890 #undef GEN_CASE
1891 default: type = "UNKNOWN";
1894 /* Store the values in the state array */
1895 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1896 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1897 /* Some special cases when one state modifies more than one... */
1898 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1899 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1900 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1903 ENTER_GL();
1905 switch (d3dTexStageStateType) {
1906 case D3DTSS_MINFILTER:
1907 case D3DTSS_MIPFILTER:
1908 if (TRACE_ON(ddraw)) {
1909 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1910 switch ((D3DTEXTUREMINFILTER) dwState) {
1911 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1912 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1913 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1915 } else {
1916 switch ((D3DTEXTUREMIPFILTER) dwState) {
1917 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1918 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1919 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1920 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1924 break;
1926 case D3DTSS_MAGFILTER:
1927 if (TRACE_ON(ddraw)) {
1928 switch ((D3DTEXTUREMAGFILTER) dwState) {
1929 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1930 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1931 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1934 break;
1936 case D3DTSS_ADDRESS:
1937 case D3DTSS_ADDRESSU:
1938 case D3DTSS_ADDRESSV: {
1939 switch ((D3DTEXTUREADDRESS) dwState) {
1940 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1941 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1942 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1943 case D3DTADDRESS_MIRROR:
1944 if (GL_extensions.mirrored_repeat) {
1945 TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1946 } else {
1947 FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1949 break;
1950 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1952 } break;
1954 case D3DTSS_ALPHAOP:
1955 case D3DTSS_COLOROP: {
1956 int scale = 1;
1957 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1958 const char *value;
1959 int handled = 1;
1961 switch (dwState) {
1962 #define GEN_CASE(a) case a: value = #a; break
1963 GEN_CASE(D3DTOP_DISABLE);
1964 GEN_CASE(D3DTOP_SELECTARG1);
1965 GEN_CASE(D3DTOP_SELECTARG2);
1966 GEN_CASE(D3DTOP_MODULATE);
1967 GEN_CASE(D3DTOP_MODULATE2X);
1968 GEN_CASE(D3DTOP_MODULATE4X);
1969 GEN_CASE(D3DTOP_ADD);
1970 GEN_CASE(D3DTOP_ADDSIGNED);
1971 GEN_CASE(D3DTOP_ADDSIGNED2X);
1972 GEN_CASE(D3DTOP_SUBTRACT);
1973 GEN_CASE(D3DTOP_ADDSMOOTH);
1974 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1975 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
1976 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
1977 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
1978 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
1979 GEN_CASE(D3DTOP_PREMODULATE);
1980 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
1981 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
1982 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
1983 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
1984 GEN_CASE(D3DTOP_BUMPENVMAP);
1985 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
1986 GEN_CASE(D3DTOP_DOTPRODUCT3);
1987 GEN_CASE(D3DTOP_FORCE_DWORD);
1988 #undef GEN_CASE
1989 default: value = "UNKNOWN";
1992 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
1993 glDisable(GL_TEXTURE_2D);
1994 TRACE(" disabling 2D texturing.\n");
1995 } else {
1996 /* Re-enable texturing only if COLOROP was not already disabled... */
1997 if ((glThis->current_bound_texture[dwStage] != NULL) &&
1998 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
1999 glEnable(GL_TEXTURE_2D);
2000 TRACE(" enabling 2D texturing.\n");
2003 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2004 if ((dwState != D3DTOP_DISABLE) &&
2005 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2006 if (glThis->current_tex_env != GL_COMBINE_EXT) {
2007 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2008 glThis->current_tex_env = GL_COMBINE_EXT;
2012 /* Now set up the operand correctly */
2013 switch (dwState) {
2014 case D3DTOP_DISABLE:
2015 /* Contrary to the docs, alpha can be disabled when colorop is enabled
2016 and it works, so ignore this op */
2017 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2018 break;
2020 case D3DTOP_SELECTARG1:
2021 case D3DTOP_SELECTARG2:
2022 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2023 break;
2025 case D3DTOP_MODULATE4X:
2026 scale = scale * 2; /* Drop through */
2027 case D3DTOP_MODULATE2X:
2028 scale = scale * 2; /* Drop through */
2029 case D3DTOP_MODULATE:
2030 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2031 break;
2033 case D3DTOP_ADD:
2034 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2035 break;
2037 case D3DTOP_ADDSIGNED2X:
2038 scale = scale * 2; /* Drop through */
2039 case D3DTOP_ADDSIGNED:
2040 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2041 break;
2043 /* For the four blending modes, use the Arg2 parameter */
2044 case D3DTOP_BLENDDIFFUSEALPHA:
2045 case D3DTOP_BLENDTEXTUREALPHA:
2046 case D3DTOP_BLENDFACTORALPHA:
2047 case D3DTOP_BLENDCURRENTALPHA: {
2048 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2050 switch (dwState) {
2051 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2052 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2053 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
2054 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2057 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2058 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2059 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2060 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2061 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2062 } break;
2064 default:
2065 handled = FALSE;
2066 break;
2070 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2071 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2072 /* Switch the arguments if needed... */
2073 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2074 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2075 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2076 dwState);
2077 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2078 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2079 dwState);
2080 } else {
2081 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2082 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2083 dwState);
2084 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2085 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2086 dwState);
2090 if (handled) {
2091 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2092 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2093 } else {
2094 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2096 TRACE(" Stage type is : %s => %s\n", type, value);
2097 } else {
2098 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2100 } break;
2102 case D3DTSS_COLORARG1:
2103 case D3DTSS_COLORARG2:
2104 case D3DTSS_ALPHAARG1:
2105 case D3DTSS_ALPHAARG2: {
2106 const char *value, *value_comp = "", *value_alpha = "";
2107 BOOLEAN handled;
2108 D3DTEXTUREOP tex_op;
2110 switch (dwState & D3DTA_SELECTMASK) {
2111 #define GEN_CASE(a) case a: value = #a; break
2112 GEN_CASE(D3DTA_DIFFUSE);
2113 GEN_CASE(D3DTA_CURRENT);
2114 GEN_CASE(D3DTA_TEXTURE);
2115 GEN_CASE(D3DTA_TFACTOR);
2116 GEN_CASE(D3DTA_SPECULAR);
2117 #undef GEN_CASE
2118 default: value = "UNKNOWN";
2120 if (dwState & D3DTA_COMPLEMENT) {
2121 value_comp = " | D3DTA_COMPLEMENT";
2123 if (dwState & D3DTA_ALPHAREPLICATE) {
2124 value_alpha = " | D3DTA_ALPHAREPLICATE";
2127 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2128 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2129 } else {
2130 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2133 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2135 if (handled) {
2136 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2137 } else {
2138 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2140 } break;
2142 case D3DTSS_MIPMAPLODBIAS: {
2143 D3DVALUE value = *((D3DVALUE *) &dwState);
2144 BOOLEAN handled = TRUE;
2146 if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2147 handled = FALSE;
2149 if (handled) {
2150 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2151 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2152 } else {
2153 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2155 } break;
2157 case D3DTSS_MAXMIPLEVEL:
2158 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2159 break;
2161 case D3DTSS_BORDERCOLOR:
2162 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2163 ((dwState >> 16) & 0xFF),
2164 ((dwState >> 8) & 0xFF),
2165 ((dwState >> 0) & 0xFF),
2166 ((dwState >> 24) & 0xFF));
2167 break;
2169 case D3DTSS_TEXCOORDINDEX: {
2170 BOOLEAN handled = TRUE;
2171 const char *value;
2173 switch (dwState & 0xFFFF0000) {
2174 #define GEN_CASE(a) case a: value = #a; break
2175 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2176 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2177 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2178 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2179 #undef GEN_CASE
2180 default: value = "UNKNOWN";
2182 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2183 handled = FALSE;
2185 if (handled) {
2186 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2187 } else {
2188 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2190 } break;
2192 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2193 const char *projected = "", *value;
2194 BOOLEAN handled = TRUE;
2195 switch (dwState & 0xFF) {
2196 #define GEN_CASE(a) case a: value = #a; break
2197 GEN_CASE(D3DTTFF_DISABLE);
2198 GEN_CASE(D3DTTFF_COUNT1);
2199 GEN_CASE(D3DTTFF_COUNT2);
2200 GEN_CASE(D3DTTFF_COUNT3);
2201 GEN_CASE(D3DTTFF_COUNT4);
2202 #undef GEN_CASE
2203 default: value = "UNKNOWN";
2205 if (dwState & D3DTTFF_PROJECTED) {
2206 projected = " | D3DTTFF_PROJECTED";
2207 handled = FALSE;
2210 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2211 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2214 if (handled) {
2215 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2216 } else {
2217 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2219 } break;
2221 default:
2222 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2223 break;
2226 LEAVE_GL();
2228 return DD_OK;
2231 static DWORD
2232 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2234 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2235 DWORD stage;
2236 BOOLEAN enable_colorkey = FALSE;
2238 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2239 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2240 GLenum unit;
2242 /* If this stage is disabled, no need to go further... */
2243 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2244 break;
2246 /* First check if we need to bind any other texture for this stage */
2247 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2248 if (This->current_texture[stage] == NULL) {
2249 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2251 unit = GL_TEXTURE0_WINE + stage;
2252 if (unit != glThis->current_active_tex_unit) {
2253 GL_extensions.glActiveTexture(unit);
2254 glThis->current_active_tex_unit = unit;
2256 glBindTexture(GL_TEXTURE_2D, 0);
2257 glDisable(GL_TEXTURE_2D);
2258 } else {
2259 GLenum tex_name = ((IDirect3DTextureGLImpl *) surf_ptr->tex_private)->tex_name;
2261 unit = GL_TEXTURE0_WINE + stage;
2262 if (unit != glThis->current_active_tex_unit) {
2263 GL_extensions.glActiveTexture(unit);
2264 glThis->current_active_tex_unit = unit;
2267 if (glThis->current_bound_texture[stage] == NULL) {
2268 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2269 TRACE(" enabling 2D texturing and");
2270 glEnable(GL_TEXTURE_2D);
2273 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2274 glBindTexture(GL_TEXTURE_2D, tex_name);
2277 glThis->current_bound_texture[stage] = This->current_texture[stage];
2278 } else {
2279 if (glThis->current_bound_texture[stage] == NULL) {
2280 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2281 } else {
2282 TRACE(" using already bound texture id %d for stage %ld.\n",
2283 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2287 /* If no texure valid for this stage, go out of the loop */
2288 if (This->current_texture[stage] == NULL) break;
2290 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2291 This will also update the various texture parameters if needed.
2293 gltex_upload_texture(surf_ptr, This, stage);
2295 /* And finally check for color-keying (only on first stage) */
2296 if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2297 if (stage == 0) {
2298 enable_colorkey = TRUE;
2299 } else {
2300 static BOOL warn = FALSE;
2301 if (warn == FALSE) {
2302 warn = TRUE;
2303 WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2306 } else {
2307 if (stage == 0) {
2308 enable_colorkey = FALSE;
2313 /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2314 if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2315 (glThis->version == 1)) &&
2316 (enable_colorkey)) {
2317 TRACE(" colorkey activated.\n");
2319 if (glThis->alpha_test == FALSE) {
2320 glEnable(GL_ALPHA_TEST);
2321 glThis->alpha_test = TRUE;
2323 if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2324 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1]) {
2325 static BOOL warn = FALSE;
2326 if (warn == FALSE) {
2327 warn = TRUE;
2328 WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2331 glThis->current_alpha_test_func = GL_NOTEQUAL;
2332 glThis->current_alpha_test_ref = 0.0;
2333 glAlphaFunc(GL_NOTEQUAL, 0.0);
2335 /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2336 Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2337 } else {
2338 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2339 glDisable(GL_ALPHA_TEST);
2340 glThis->alpha_test = FALSE;
2342 /* Maybe we should restore here the application-given alpha test states ? */
2345 return stage;
2348 HRESULT WINAPI
2349 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2350 DWORD dwStage,
2351 LPDIRECTDRAWSURFACE7 lpTexture2)
2353 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2355 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2357 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2358 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2359 if (lpTexture2 != NULL) {
2360 WARN(" setting a texture to a non-supported texture stage !\n");
2362 return DD_OK;
2365 if (This->current_texture[dwStage] != NULL) {
2366 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2369 if (lpTexture2 == NULL) {
2370 This->current_texture[dwStage] = NULL;
2371 } else {
2372 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2373 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2374 This->current_texture[dwStage] = tex_impl;
2377 return DD_OK;
2380 HRESULT WINAPI
2381 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2382 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2384 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2385 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2387 fill_opengl_caps_7(lpD3DHELDevDesc);
2389 TRACE(" returning caps : no dump function yet.\n");
2391 return DD_OK;
2394 HRESULT WINAPI
2395 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2396 LPD3DMATERIAL7 lpMat)
2398 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2399 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2401 if (TRACE_ON(ddraw)) {
2402 TRACE(" material is : \n");
2403 dump_D3DMATERIAL7(lpMat);
2406 This->current_material = *lpMat;
2408 ENTER_GL();
2409 glMaterialfv(GL_FRONT_AND_BACK,
2410 GL_DIFFUSE,
2411 (float *) &(This->current_material.u.diffuse));
2412 glMaterialfv(GL_FRONT_AND_BACK,
2413 GL_AMBIENT,
2414 (float *) &(This->current_material.u1.ambient));
2415 glMaterialfv(GL_FRONT_AND_BACK,
2416 GL_SPECULAR,
2417 (float *) &(This->current_material.u2.specular));
2418 glMaterialfv(GL_FRONT_AND_BACK,
2419 GL_EMISSION,
2420 (float *) &(This->current_material.u3.emissive));
2421 glMaterialf(GL_FRONT_AND_BACK,
2422 GL_SHININESS,
2423 This->current_material.u4.power); /* Not sure about this... */
2424 LEAVE_GL();
2426 return DD_OK;
2430 HRESULT WINAPI
2431 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2432 DWORD dwLightIndex,
2433 LPD3DLIGHT7 lpLight)
2435 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2436 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2437 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2439 if (TRACE_ON(ddraw)) {
2440 TRACE(" setting light : \n");
2441 dump_D3DLIGHT7(lpLight);
2444 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2445 This->set_lights |= 0x00000001 << dwLightIndex;
2446 This->light_parameters[dwLightIndex] = *lpLight;
2448 /* Some checks to print out nice warnings :-) */
2449 switch (lpLight->dltType) {
2450 case D3DLIGHT_DIRECTIONAL:
2451 case D3DLIGHT_POINT:
2452 /* These are handled properly... */
2453 break;
2455 case D3DLIGHT_SPOT:
2456 if ((lpLight->dvTheta != 0.0) ||
2457 (lpLight->dvTheta != lpLight->dvPhi)) {
2458 ERR("dvTheta not fully supported yet !\n");
2460 break;
2462 default:
2463 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2466 /* This will force the Light setting on next drawing of primitives */
2467 glThis->transform_state = GL_TRANSFORM_NONE;
2469 return DD_OK;
2472 HRESULT WINAPI
2473 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2474 DWORD dwLightIndex,
2475 BOOL bEnable)
2477 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2478 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2480 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2482 ENTER_GL();
2483 if (bEnable) {
2484 if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
2485 /* Set the default parameters.. */
2486 TRACE(" setting default light parameters...\n");
2487 GL_IDirect3DDeviceImpl_7_SetLight(iface, dwLightIndex, &(This->light_parameters[dwLightIndex]));
2489 glEnable(GL_LIGHT0 + dwLightIndex);
2490 if ((This->active_lights & (0x00000001 << dwLightIndex)) == 0) {
2491 /* This light gets active... Need to update its parameters to GL before the next drawing */
2492 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2494 This->active_lights |= 0x00000001 << dwLightIndex;
2495 glThis->transform_state = GL_TRANSFORM_NONE;
2497 } else {
2498 glDisable(GL_LIGHT0 + dwLightIndex);
2499 This->active_lights &= ~(0x00000001 << dwLightIndex);
2501 LEAVE_GL();
2503 return DD_OK;
2506 HRESULT WINAPI
2507 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2509 IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2510 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2512 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2514 if (dwIndex >= This->max_clipping_planes) {
2515 return DDERR_INVALIDPARAMS;
2518 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2520 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2522 /* This is to force the reset of the transformation matrices on the next drawing.
2523 * This is needed to use the correct matrices for the various clipping planes.
2525 glThis->transform_state = GL_TRANSFORM_NONE;
2527 return D3D_OK;
2530 HRESULT WINAPI
2531 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2532 LPD3DVIEWPORT7 lpData)
2534 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2535 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2537 if (TRACE_ON(ddraw)) {
2538 TRACE(" viewport is : \n");
2539 TRACE(" - dwX = %ld dwY = %ld\n",
2540 lpData->dwX, lpData->dwY);
2541 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2542 lpData->dwWidth, lpData->dwHeight);
2543 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2544 lpData->dvMinZ, lpData->dvMaxZ);
2546 ENTER_GL();
2548 /* Set the viewport */
2549 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2550 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2551 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2553 if ((lpData->dwX != This->active_viewport.dwX) ||
2554 (lpData->dwY != This->active_viewport.dwY) ||
2555 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2556 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2557 glViewport(lpData->dwX,
2558 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2559 lpData->dwWidth, lpData->dwHeight);
2562 LEAVE_GL();
2564 This->active_viewport = *lpData;
2566 return DD_OK;
2569 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2570 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2571 #else
2572 # define XCAST(fun) (void*)
2573 #endif
2575 IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2577 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2578 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2579 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2580 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2581 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2582 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2583 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2584 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2585 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2586 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2587 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2588 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2589 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2590 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2591 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2592 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2593 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2594 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2595 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2596 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2597 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2598 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2599 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2600 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2601 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2602 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2603 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2604 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2605 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2606 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2607 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2608 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2609 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2610 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2611 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2612 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2613 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2614 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2615 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2616 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2617 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2618 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2619 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2620 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2621 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2622 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2623 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2624 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2625 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2628 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2629 #undef XCAST
2630 #endif
2633 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2634 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2635 #else
2636 # define XCAST(fun) (void*)
2637 #endif
2639 IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2641 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2642 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2643 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2644 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2645 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2646 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2647 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2648 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2649 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2650 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2651 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2652 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2653 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2654 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2655 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2656 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2657 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2658 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2659 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2660 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2661 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2662 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2663 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2664 XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2665 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2666 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2667 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2668 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2669 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2670 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2671 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2672 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2673 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2674 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2675 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2676 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2677 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2678 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2679 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2680 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2681 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2682 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2685 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2686 #undef XCAST
2687 #endif
2690 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2691 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2692 #else
2693 # define XCAST(fun) (void*)
2694 #endif
2696 IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2698 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2699 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2700 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2701 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2702 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2703 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2704 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2705 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2706 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2707 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2708 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2709 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2710 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2711 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2712 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2713 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2714 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2715 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2716 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2717 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2718 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2719 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2720 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2721 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2722 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2723 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2724 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2725 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2726 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2727 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2728 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2729 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2730 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2733 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2734 #undef XCAST
2735 #endif
2738 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2739 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2740 #else
2741 # define XCAST(fun) (void*)
2742 #endif
2744 IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2746 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2747 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2748 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2749 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2750 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2751 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2752 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2753 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2754 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2755 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2756 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2757 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2758 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2759 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2760 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2761 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2762 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2763 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2764 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2765 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2766 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2767 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2770 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2771 #undef XCAST
2772 #endif
2774 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2775 WINE_GL_BUFFER_TYPE buffer_type,
2776 DWORD dwCount,
2777 LPD3DRECT lpRects,
2778 DWORD dwFlags,
2779 DWORD dwColor,
2780 D3DVALUE dvZ,
2781 DWORD dwStencil)
2783 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2784 GLbitfield bitfield = 0;
2785 D3DRECT rect;
2786 unsigned int i;
2788 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2789 if (TRACE_ON(ddraw)) {
2790 if (dwCount > 0) {
2791 unsigned int i;
2792 TRACE(" rectangles : \n");
2793 for (i = 0; i < dwCount; i++) {
2794 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2799 if (dwCount == 0) {
2800 dwCount = 1;
2801 rect.u1.x1 = 0;
2802 rect.u2.y1 = 0;
2803 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2804 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2805 lpRects = &rect;
2808 /* Clears the screen */
2809 ENTER_GL();
2811 if (dwFlags & D3DCLEAR_TARGET) {
2812 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2813 /* TODO: optimize here the case where Clear changes all the screen... */
2814 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2816 glThis->state[buffer_type] = SURFACE_GL;
2819 if (dwFlags & D3DCLEAR_ZBUFFER) {
2820 bitfield |= GL_DEPTH_BUFFER_BIT;
2821 if (glThis->depth_mask == FALSE) {
2822 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2824 if (dvZ != glThis->prev_clear_Z) {
2825 glClearDepth(dvZ);
2826 glThis->prev_clear_Z = dvZ;
2828 TRACE(" depth value : %f\n", dvZ);
2830 if (dwFlags & D3DCLEAR_STENCIL) {
2831 bitfield |= GL_STENCIL_BUFFER_BIT;
2832 if (dwStencil != glThis->prev_clear_stencil) {
2833 glClearStencil(dwStencil);
2834 glThis->prev_clear_stencil = dwStencil;
2836 TRACE(" stencil value : %ld\n", dwStencil);
2838 if (dwFlags & D3DCLEAR_TARGET) {
2839 bitfield |= GL_COLOR_BUFFER_BIT;
2840 if (dwColor != glThis->prev_clear_color) {
2841 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2842 ((dwColor >> 8) & 0xFF) / 255.0,
2843 ((dwColor >> 0) & 0xFF) / 255.0,
2844 ((dwColor >> 24) & 0xFF) / 255.0);
2845 glThis->prev_clear_color = dwColor;
2847 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2850 glEnable(GL_SCISSOR_TEST);
2851 for (i = 0; i < dwCount; i++) {
2852 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2853 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2854 glClear(bitfield);
2856 glDisable(GL_SCISSOR_TEST);
2858 if (dwFlags & D3DCLEAR_ZBUFFER) {
2859 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2862 LEAVE_GL();
2864 return DD_OK;
2867 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2868 DWORD dwCount,
2869 LPD3DRECT lpRects,
2870 DWORD dwFlags,
2871 DWORD dwColor,
2872 D3DVALUE dvZ,
2873 DWORD dwStencil)
2875 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2878 static HRESULT
2879 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2880 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2882 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2883 WINE_GL_BUFFER_TYPE buffer_type;
2885 /* First check if we BLT to the backbuffer... */
2886 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2887 buffer_type = WINE_GL_BUFFER_BACK;
2888 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2889 buffer_type = WINE_GL_BUFFER_FRONT;
2890 } else {
2891 ERR("Only BLT override to front or back-buffer is supported for now !\n");
2892 return DDERR_INVALIDPARAMS;
2895 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
2896 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
2897 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
2898 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
2899 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
2900 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
2901 * GL to do it.
2903 return DDERR_INVALIDPARAMS;
2905 *buffer_type_p = buffer_type;
2907 return DD_OK;
2910 HRESULT
2911 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
2912 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
2913 DWORD dwFlags, LPDDBLTFX lpbltfx)
2915 WINE_GL_BUFFER_TYPE buffer_type;
2916 D3DRECT rect;
2918 if (rdst) {
2919 rect.u1.x1 = rdst->left;
2920 rect.u2.y1 = rdst->top;
2921 rect.u3.x2 = rdst->right;
2922 rect.u4.y2 = rdst->bottom;
2923 } else {
2924 rect.u1.x1 = 0;
2925 rect.u2.y1 = 0;
2926 rect.u3.x2 = This->surface_desc.dwWidth;
2927 rect.u4.y2 = This->surface_desc.dwHeight;
2930 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
2932 if (dwFlags & DDBLT_COLORFILL) {
2933 /* This is easy to handle for the D3D Device... */
2934 DWORD color;
2935 GLenum prev_draw;
2937 /* The color as given in the Blt function is in the format of the frame-buffer...
2938 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2940 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
2941 if (This->palette) {
2942 color = ((0xFF000000) |
2943 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
2944 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
2945 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
2946 } else {
2947 color = 0xFF000000;
2949 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
2950 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
2951 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
2952 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
2953 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
2954 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
2955 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
2956 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
2957 color = 0xFFFFFFFF;
2958 } else {
2959 color = ((0xFF000000) |
2960 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
2961 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
2962 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
2964 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
2965 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
2966 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
2967 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
2968 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
2969 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
2970 } else {
2971 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
2972 return DDERR_INVALIDPARAMS;
2974 } else {
2975 ERR("Wrong surface type for BLT override !\n");
2976 return DDERR_INVALIDPARAMS;
2979 TRACE(" executing D3D Device override.\n");
2981 ENTER_GL();
2983 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2984 if (buffer_type == WINE_GL_BUFFER_FRONT)
2985 glDrawBuffer(GL_FRONT);
2986 else
2987 glDrawBuffer(GL_BACK);
2989 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
2991 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
2992 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
2993 glDrawBuffer(prev_draw);
2995 LEAVE_GL();
2997 return DD_OK;
2998 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
2999 /* Normal blit without any special case... */
3000 if (src != NULL) {
3001 /* And which has a SRC surface */
3002 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3004 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3005 (src_impl->d3ddevice == This->d3ddevice) &&
3006 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3007 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3008 D3DRECT src_rect;
3009 int width, height;
3010 GLenum prev_draw;
3011 WINE_GL_BUFFER_TYPE src_buffer_type;
3012 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3013 BOOLEAN initial;
3014 DWORD opt_bitmap;
3015 int x, y;
3017 if (rsrc) {
3018 src_rect.u1.x1 = rsrc->left;
3019 src_rect.u2.y1 = rsrc->top;
3020 src_rect.u3.x2 = rsrc->right;
3021 src_rect.u4.y2 = rsrc->bottom;
3022 } else {
3023 src_rect.u1.x1 = 0;
3024 src_rect.u2.y1 = 0;
3025 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3026 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3029 width = src_rect.u3.x2 - src_rect.u1.x1;
3030 height = src_rect.u4.y2 - src_rect.u2.y1;
3032 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3033 (height != (rect.u4.y2 - rect.u2.y1))) {
3034 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3035 return DDERR_INVALIDPARAMS;
3038 /* First check if we BLT from the backbuffer... */
3039 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3040 src_buffer_type = WINE_GL_BUFFER_BACK;
3041 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3042 src_buffer_type = WINE_GL_BUFFER_FRONT;
3043 } else {
3044 ERR("Unexpected case in direct buffer to buffer copy !\n");
3045 return DDERR_INVALIDPARAMS;
3048 TRACE(" using direct buffer to buffer copy.\n");
3050 ENTER_GL();
3052 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3054 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3055 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3056 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3057 LEAVE_GL();
3058 return DDERR_INVALIDPARAMS;
3061 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3062 if (buffer_type == WINE_GL_BUFFER_FRONT)
3063 glDrawBuffer(GL_FRONT);
3064 else
3065 glDrawBuffer(GL_BACK);
3067 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3068 glReadBuffer(GL_FRONT);
3069 else
3070 glReadBuffer(GL_BACK);
3072 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3073 And directly re-draws this on the destination buffer. */
3074 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3075 int get_height;
3077 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3078 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3079 else
3080 get_height = UNLOCK_TEX_SIZE;
3082 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3083 int get_width;
3085 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3086 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3087 else
3088 get_width = UNLOCK_TEX_SIZE;
3090 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3091 0, UNLOCK_TEX_SIZE - get_height,
3092 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3093 get_width, get_height);
3095 glBegin(GL_QUADS);
3096 glTexCoord2f(0.0, 0.0);
3097 glVertex3d(rect.u1.x1 + x,
3098 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3099 0.5);
3100 glTexCoord2f(1.0, 0.0);
3101 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3102 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3103 0.5);
3104 glTexCoord2f(1.0, 1.0);
3105 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3106 rect.u2.y1 + y,
3107 0.5);
3108 glTexCoord2f(0.0, 1.0);
3109 glVertex3d(rect.u1.x1 + x,
3110 rect.u2.y1 + y,
3111 0.5);
3112 glEnd();
3116 upload_surface_to_tex_memory_release();
3117 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3119 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3120 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3121 glDrawBuffer(prev_draw);
3123 LEAVE_GL();
3125 return DD_OK;
3126 } else {
3127 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3128 (this prevents calling glReadPixels) */
3129 D3DRECT src_rect;
3130 int width, height;
3131 GLenum prev_draw;
3132 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3133 BOOLEAN initial;
3134 DWORD opt_bitmap;
3135 int x, y;
3136 double x_stretch, y_stretch;
3138 if (rsrc) {
3139 src_rect.u1.x1 = rsrc->left;
3140 src_rect.u2.y1 = rsrc->top;
3141 src_rect.u3.x2 = rsrc->right;
3142 src_rect.u4.y2 = rsrc->bottom;
3143 } else {
3144 src_rect.u1.x1 = 0;
3145 src_rect.u2.y1 = 0;
3146 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3147 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3150 width = src_rect.u3.x2 - src_rect.u1.x1;
3151 height = src_rect.u4.y2 - src_rect.u2.y1;
3153 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3154 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3156 TRACE(" using memory to buffer Blt override.\n");
3158 ENTER_GL();
3160 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3162 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3163 initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3164 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3165 LEAVE_GL();
3166 return DDERR_INVALIDPARAMS;
3169 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3170 if (buffer_type == WINE_GL_BUFFER_FRONT)
3171 glDrawBuffer(GL_FRONT);
3172 else
3173 glDrawBuffer(GL_BACK);
3175 /* Now the serious stuff happens. This is basically the same code as for the memory
3176 flush to frame buffer ... with stretching and different rectangles added :-) */
3177 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3178 RECT flush_rect;
3180 flush_rect.top = src_rect.u2.y1 + y;
3181 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3182 src_rect.u4.y2 :
3183 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3185 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3186 flush_rect.left = src_rect.u1.x1 + x;
3187 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3188 src_rect.u3.x2 :
3189 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3191 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3193 glBegin(GL_QUADS);
3194 glTexCoord2f(0.0, 0.0);
3195 glVertex3d(rect.u1.x1 + (x * x_stretch),
3196 rect.u2.y1 + (y * y_stretch),
3197 0.5);
3198 glTexCoord2f(1.0, 0.0);
3199 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3200 rect.u2.y1 + (y * y_stretch),
3201 0.5);
3202 glTexCoord2f(1.0, 1.0);
3203 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3204 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3205 0.5);
3206 glTexCoord2f(0.0, 1.0);
3207 glVertex3d(rect.u1.x1 + (x * x_stretch),
3208 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3209 0.5);
3210 glEnd();
3214 upload_surface_to_tex_memory_release();
3215 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3217 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3218 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3219 glDrawBuffer(prev_draw);
3221 LEAVE_GL();
3223 return DD_OK;
3227 return DDERR_INVALIDPARAMS;
3230 HRESULT
3231 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3232 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3233 LPRECT rsrc, DWORD trans)
3235 RECT rsrc2;
3236 RECT rdst;
3237 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3238 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3239 WINE_GL_BUFFER_TYPE buffer_type;
3240 GLenum prev_draw;
3241 DWORD opt_bitmap;
3242 BOOLEAN initial;
3243 int width, height, x, y;
3245 /* Cannot support DSTCOLORKEY blitting... */
3246 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3248 if (rsrc == NULL) {
3249 WARN("rsrc is NULL - getting the whole surface !!\n");
3250 rsrc = &rsrc2;
3251 rsrc->left = rsrc->top = 0;
3252 rsrc->right = src_impl->surface_desc.dwWidth;
3253 rsrc->bottom = src_impl->surface_desc.dwHeight;
3254 } else {
3255 rsrc2 = *rsrc;
3256 rsrc = &rsrc2;
3259 rdst.left = dstx;
3260 rdst.top = dsty;
3261 rdst.right = dstx + (rsrc->right - rsrc->left);
3262 if (rdst.right > This->surface_desc.dwWidth) {
3263 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3264 rdst.right = This->surface_desc.dwWidth;
3266 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3267 if (rdst.bottom > This->surface_desc.dwHeight) {
3268 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3269 rdst.bottom = This->surface_desc.dwHeight;
3272 width = rsrc->right - rsrc->left;
3273 height = rsrc->bottom - rsrc->top;
3275 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3277 TRACE(" using BltFast memory to frame buffer override.\n");
3279 ENTER_GL();
3281 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3283 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3284 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3285 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3286 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3287 LEAVE_GL();
3288 return DDERR_INVALIDPARAMS;
3291 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3292 if (buffer_type == WINE_GL_BUFFER_FRONT)
3293 glDrawBuffer(GL_FRONT);
3294 else
3295 glDrawBuffer(GL_BACK);
3297 /* Now the serious stuff happens. This is basically the same code that for the memory
3298 flush to frame buffer but with different rectangles for source and destination :-) */
3299 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3300 RECT flush_rect;
3302 flush_rect.top = rsrc->top + y;
3303 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3304 rsrc->bottom :
3305 (rsrc->top + y + UNLOCK_TEX_SIZE));
3307 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3308 flush_rect.left = rsrc->left + x;
3309 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3310 rsrc->right :
3311 (rsrc->left + x + UNLOCK_TEX_SIZE));
3313 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3315 glBegin(GL_QUADS);
3316 glTexCoord2f(0.0, 0.0);
3317 glVertex3d(rdst.left + x,
3318 rdst.top + y,
3319 0.5);
3320 glTexCoord2f(1.0, 0.0);
3321 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3322 rdst.top + y,
3323 0.5);
3324 glTexCoord2f(1.0, 1.0);
3325 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3326 rdst.top + (y + UNLOCK_TEX_SIZE),
3327 0.5);
3328 glTexCoord2f(0.0, 1.0);
3329 glVertex3d(rdst.left + x,
3330 rdst.top + (y + UNLOCK_TEX_SIZE),
3331 0.5);
3332 glEnd();
3336 upload_surface_to_tex_memory_release();
3337 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3339 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3340 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3341 glDrawBuffer(prev_draw);
3343 LEAVE_GL();
3345 return DD_OK;
3348 void
3349 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3351 GLfloat height, width;
3352 GLfloat trans_mat[16];
3354 TRACE("(%p)\n", This);
3356 width = This->surface->surface_desc.dwWidth;
3357 height = This->surface->surface_desc.dwHeight;
3359 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3360 * to OpenGL screen coordinates (ie the upper left corner is not the same).
3362 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3363 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3364 #if 0
3365 /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3366 * that the Z coordinate needs to be given to GL unchanged.
3368 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 2.0; trans_mat[14] = -1.0;
3369 #endif
3370 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = 0.0;
3371 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3373 ENTER_GL();
3374 glMatrixMode(GL_MODELVIEW);
3375 glLoadIdentity();
3376 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3377 Correctness Tips section).
3379 Basically, from what I understood, if the game does not filter the font texture,
3380 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3381 one and we will have strange artifacts (as the rounding and stuff may give different results
3382 for different pixels, ie sometimes take the left pixel, sometimes the right).
3384 glTranslatef(0.375, 0.375, 0);
3385 glMatrixMode(GL_PROJECTION);
3386 glLoadMatrixf(trans_mat);
3387 LEAVE_GL();
3390 void
3391 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3392 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3394 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3396 ENTER_GL();
3397 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3398 glMatrixMode(GL_MODELVIEW);
3399 glLoadMatrixf((float *) view_mat);
3401 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3402 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3403 GLint i;
3404 DWORD runner;
3405 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3406 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3407 GLdouble plane[4];
3409 plane[0] = This->clipping_planes[i].plane[0];
3410 plane[1] = This->clipping_planes[i].plane[1];
3411 plane[2] = This->clipping_planes[i].plane[2];
3412 plane[3] = This->clipping_planes[i].plane[3];
3414 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3418 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3419 GLint i;
3420 DWORD runner;
3422 for (i = 0, runner = 0x00000001; i < MAX_LIGHTS; i++, runner <<= 1) {
3423 if (runner & This->active_lights) {
3424 switch (This->light_parameters[i].dltType) {
3425 case D3DLIGHT_DIRECTIONAL: {
3426 float direction[4];
3427 float cut_off = 180.0;
3429 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3430 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3431 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3432 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3434 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3435 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3436 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3437 direction[3] = 0.0;
3438 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3439 } break;
3441 case D3DLIGHT_POINT: {
3442 float position[4];
3443 float cut_off = 180.0;
3445 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3446 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3447 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3448 position[0] = This->light_parameters[i].dvPosition.u1.x;
3449 position[1] = This->light_parameters[i].dvPosition.u2.y;
3450 position[2] = This->light_parameters[i].dvPosition.u3.z;
3451 position[3] = 1.0;
3452 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3453 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3454 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3455 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3456 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3457 } break;
3459 case D3DLIGHT_SPOT: {
3460 float direction[4];
3461 float position[4];
3462 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3464 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3465 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3466 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3468 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3469 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3470 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3471 direction[3] = 0.0;
3472 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3473 position[0] = This->light_parameters[i].dvPosition.u1.x;
3474 position[1] = This->light_parameters[i].dvPosition.u2.y;
3475 position[2] = This->light_parameters[i].dvPosition.u3.z;
3476 position[3] = 1.0;
3477 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3478 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3479 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3480 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3481 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3482 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &(This->light_parameters[i].dvFalloff));
3483 } break;
3485 default:
3486 /* No warning here as it's already done at light setting */
3487 break;
3493 glMultMatrixf((float *) world_mat);
3495 if ((matrices & PROJMAT_CHANGED) != 0) {
3496 glMatrixMode(GL_PROJECTION);
3497 glLoadMatrixf((float *) proj_mat);
3499 LEAVE_GL();
3502 void
3503 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3505 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3506 DWORD tex_mat, tex_stage;
3508 TRACE("(%p,%08lx)\n", This, matrices);
3510 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3511 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3512 /* This will force an update of the transform state at the next drawing. */
3513 glThis->transform_state = GL_TRANSFORM_NONE;
3516 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3517 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3519 ENTER_GL();
3520 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3521 GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3522 if (matrices & tex_mat) {
3523 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3524 int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3526 if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3527 if (glThis->current_active_tex_unit != unit) {
3528 GL_extensions.glActiveTexture(unit);
3529 glThis->current_active_tex_unit = unit;
3531 glMatrixMode(GL_TEXTURE);
3532 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3534 This->tex_mat_is_identity[tex_stage] = is_identity;
3535 } else {
3536 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3537 if (glThis->current_active_tex_unit != unit) {
3538 GL_extensions.glActiveTexture(unit);
3539 glThis->current_active_tex_unit = unit;
3541 glMatrixMode(GL_TEXTURE);
3542 glLoadIdentity();
3543 This->tex_mat_is_identity[tex_stage] = TRUE;
3548 LEAVE_GL();
3552 /* TODO for both these functions :
3553 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3554 by other OpenGL code in D3D
3555 - handle the case where no 'Begin / EndScene' was done between two locks
3556 - handle the rectangles in the unlock too
3557 - handle pitch correctly...
3559 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3561 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3562 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3563 WINE_GL_BUFFER_TYPE buffer_type;
3564 RECT loc_rect;
3566 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3567 buffer_type = WINE_GL_BUFFER_FRONT;
3568 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3569 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3570 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3572 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3573 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3574 buffer_type = WINE_GL_BUFFER_BACK;
3575 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3576 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3577 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3579 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3580 } else {
3581 ERR("Wrong surface type for locking !\n");
3582 return;
3585 if (pRect == NULL) {
3586 loc_rect.top = 0;
3587 loc_rect.left = 0;
3588 loc_rect.bottom = This->surface_desc.dwHeight;
3589 loc_rect.right = This->surface_desc.dwWidth;
3590 pRect = &loc_rect;
3593 /* Try to acquire the device critical section */
3594 EnterCriticalSection(&(d3d_dev->crit));
3596 if (gl_d3d_dev->lock_rect_valid[buffer_type]) {
3597 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3598 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3600 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3602 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3603 /* Check if the new rectangle is in the previous one or not.
3604 If it is not, flush first the previous locks on screen.
3606 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3607 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3608 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3609 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3610 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3611 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3612 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3613 pRect->left, pRect->top, pRect->right, pRect->bottom,
3614 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3615 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3616 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3618 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3619 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3621 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3622 } else {
3623 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3626 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3627 /* If the surface is already in memory, no need to do anything here... */
3628 GLenum buffer_format;
3629 GLenum buffer_color;
3630 int y;
3631 char *dst;
3633 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3634 pRect->left, pRect->top, pRect->right, pRect->bottom);
3636 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3637 may only write to the device... But when we will blit it back to the screen, we need
3638 also to blit correctly the parts the application did not overwrite... */
3640 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3641 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3642 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3643 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3644 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3645 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3646 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3647 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3648 buffer_color = GL_RGB;
3649 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3650 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3651 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3652 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3653 buffer_format = GL_UNSIGNED_BYTE;
3654 buffer_color = GL_RGB;
3655 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3656 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3657 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3658 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3659 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3660 buffer_color = GL_BGRA;
3661 } else {
3662 ERR(" unsupported pixel format at device locking.\n");
3663 return;
3665 } else {
3666 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3667 return;
3670 ENTER_GL();
3672 if (buffer_type == WINE_GL_BUFFER_FRONT)
3673 /* Application wants to lock the front buffer */
3674 glReadBuffer(GL_FRONT);
3675 else
3676 /* Application wants to lock the back buffer */
3677 glReadBuffer(GL_BACK);
3679 dst = ((char *)This->surface_desc.lpSurface) +
3680 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3682 if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3683 /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3684 * could not be bothered considering the rare cases where it may be useful :-)
3686 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3687 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3688 y--) {
3689 glReadPixels(pRect->left, y,
3690 pRect->right - pRect->left, 1,
3691 buffer_color, buffer_format, dst);
3692 dst += This->surface_desc.u1.lPitch;
3694 } else {
3695 /* Faster path for surface copy. Note that I can use static variables here as I am
3696 * protected by the OpenGL critical section so this function won't be called by
3697 * two threads at the same time.
3699 static char *buffer = NULL;
3700 static int buffer_width = 0;
3701 char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3702 int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3704 glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3705 pRect->right - pRect->left, pRect->bottom - pRect->top,
3706 buffer_color, buffer_format, dst);
3708 if (current_width > buffer_width) {
3709 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3710 buffer_width = current_width;
3711 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3713 for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3714 memcpy(buffer, dst, current_width);
3715 memcpy(dst, dst2, current_width);
3716 memcpy(dst2, buffer, current_width);
3717 dst += This->surface_desc.u1.lPitch;
3718 dst2 -= This->surface_desc.u1.lPitch;
3722 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3724 #if 0
3725 /* I keep this code here as it's very useful to debug :-) */
3727 static int flush_count = 0;
3728 char buf[128];
3729 FILE *f;
3731 if ((++flush_count % 50) == 0) {
3732 sprintf(buf, "lock_%06d.pnm", flush_count);
3733 f = fopen(buf, "wb");
3734 DDRAW_dump_surface_to_disk(This, f);
3737 #endif
3739 LEAVE_GL();
3743 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3744 RECT loc_rect;
3745 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3746 int x, y;
3747 BOOLEAN initial;
3748 DWORD opt_bitmap;
3750 /* Note : no need here to lock the 'device critical section' as we are already protected by
3751 the GL critical section. */
3753 if (pRect == NULL) {
3754 loc_rect.top = 0;
3755 loc_rect.left = 0;
3756 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3757 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3758 pRect = &loc_rect;
3761 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3763 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3765 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3766 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3767 ERR(" unsupported pixel format at frame buffer flush.\n");
3768 return;
3771 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3772 RECT flush_rect;
3774 flush_rect.top = y;
3775 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3777 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3778 /* First, upload the texture... */
3779 flush_rect.left = x;
3780 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3782 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3784 glBegin(GL_QUADS);
3785 glTexCoord2f(0.0, 0.0);
3786 glVertex3d(x, y, 0.5);
3787 glTexCoord2f(1.0, 0.0);
3788 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3789 glTexCoord2f(1.0, 1.0);
3790 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3791 glTexCoord2f(0.0, 1.0);
3792 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3793 glEnd();
3797 upload_surface_to_tex_memory_release();
3798 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3800 #if 0
3801 /* I keep this code here as it's very useful to debug :-) */
3803 static int flush_count = 0;
3804 char buf[128];
3805 FILE *f;
3807 if ((++flush_count % 50) == 0) {
3808 sprintf(buf, "flush_%06d.pnm", flush_count);
3809 f = fopen(buf, "wb");
3810 DDRAW_dump_surface_to_disk(surf, f);
3813 #endif
3816 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3818 WINE_GL_BUFFER_TYPE buffer_type;
3819 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3820 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3822 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3823 buffer_type = WINE_GL_BUFFER_FRONT;
3824 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3825 buffer_type = WINE_GL_BUFFER_BACK;
3826 } else {
3827 ERR("Wrong surface type for locking !\n");
3828 return;
3831 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3832 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3833 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3835 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3837 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3838 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3839 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3840 GLenum prev_draw;
3842 TRACE(" flushing front buffer immediately on screen.\n");
3844 ENTER_GL();
3845 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3846 glDrawBuffer(GL_FRONT);
3847 /* Note: we do not use the application provided lock rectangle but our own stored at
3848 lock time. This is because in old D3D versions, the 'lock' parameter did not
3849 exist.
3851 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_FRONT]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT]);
3852 glDrawBuffer(prev_draw);
3853 LEAVE_GL();
3854 } else {
3855 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3859 /* And 'frees' the device critical section */
3860 LeaveCriticalSection(&(d3d_dev->crit));
3863 static void
3864 apply_texture_state(IDirect3DDeviceImpl *This)
3866 int stage, state;
3868 /* Initialize texture stages states */
3869 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3870 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3871 if (This->state_block.set_flags.texture_stage_state[stage][state]) {
3872 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3873 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3879 HRESULT
3880 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, BOOLEAN from_surface)
3882 IDirect3DDeviceImpl *object;
3883 IDirect3DDeviceGLImpl *gl_object;
3884 IDirectDrawSurfaceImpl *surf;
3885 HDC device_context;
3886 XVisualInfo *vis;
3887 int num;
3888 int tex_num;
3889 XVisualInfo template;
3890 GLenum buffer = GL_FRONT;
3891 int light;
3893 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
3894 if (object == NULL) return DDERR_OUTOFMEMORY;
3896 gl_object = (IDirect3DDeviceGLImpl *) object;
3898 object->ref = 1;
3899 object->d3d = d3d;
3900 object->surface = surface;
3901 object->set_context = set_context;
3902 object->clear = d3ddevice_clear_back;
3903 object->set_matrices = d3ddevice_set_matrices;
3904 object->matrices_updated = d3ddevice_matrices_updated;
3905 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
3907 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
3909 InitializeCriticalSection(&(object->crit));
3911 TRACE(" device critical section : %p\n", &(object->crit));
3913 /* This is just a hack for some badly done games :-/ */
3914 if (from_surface) {
3915 gl_object->version = 1;
3916 TRACE(" using D3D1 special hacks.\n");
3917 } else
3918 gl_object->version = 7;
3920 device_context = GetDC(surface->ddraw_owner->window);
3921 gl_object->display = get_display(device_context);
3922 gl_object->drawable = get_drawable(device_context);
3923 ReleaseDC(surface->ddraw_owner->window,device_context);
3925 ENTER_GL();
3926 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
3927 vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
3928 if (vis == NULL) {
3929 HeapFree(GetProcessHeap(), 0, object);
3930 ERR("No visual found !\n");
3931 LEAVE_GL();
3932 return DDERR_INVALIDPARAMS;
3933 } else {
3934 TRACE(" visual found\n");
3937 gl_object->gl_context = glXCreateContext(gl_object->display, vis,
3938 NULL, GL_TRUE);
3940 if (gl_object->gl_context == NULL) {
3941 HeapFree(GetProcessHeap(), 0, object);
3942 ERR("Error in context creation !\n");
3943 LEAVE_GL();
3944 return DDERR_INVALIDPARAMS;
3945 } else {
3946 TRACE(" context created (%p)\n", gl_object->gl_context);
3949 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
3950 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3951 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
3952 surf->aux_ctx = (LPVOID) object;
3953 surf->aux_data = (LPVOID) gl_object->drawable;
3954 surf->aux_flip = opengl_flip;
3955 buffer = GL_BACK;
3956 break;
3959 /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
3960 if (surf == NULL) {
3961 TRACE(" no double buffering : drawing on the front buffer\n");
3962 buffer = GL_FRONT;
3965 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3966 IDirectDrawSurfaceImpl *surf2;
3967 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
3968 for (; surf2 != NULL; surf2 = surf2->next_attached) {
3969 TRACE(" checking surface %p :", surf2);
3970 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
3971 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
3972 /* Override the Lock / Unlock function for all these surfaces */
3973 surf2->lock_update_prev = surf2->lock_update;
3974 surf2->lock_update = d3ddevice_lock_update;
3975 surf2->unlock_update_prev = surf2->unlock_update;
3976 surf2->unlock_update = d3ddevice_unlock_update;
3977 /* And install also the blt / bltfast overrides */
3978 surf2->aux_blt = d3ddevice_blt;
3979 surf2->aux_bltfast = d3ddevice_bltfast;
3981 TRACE(" overriding direct surface access.\n");
3982 } else {
3983 TRACE(" no override.\n");
3985 surf2->d3ddevice = object;
3989 /* Set the various light parameters */
3990 for (light = 0; light < MAX_LIGHTS; light++) {
3991 /* Only set the fields that are not zero-created */
3992 object->light_parameters[light].dltType = D3DLIGHT_DIRECTIONAL;
3993 object->light_parameters[light].dcvDiffuse.u1.r = 1.0;
3994 object->light_parameters[light].dcvDiffuse.u2.g = 1.0;
3995 object->light_parameters[light].dcvDiffuse.u3.b = 1.0;
3996 object->light_parameters[light].dvDirection.u3.z = 1.0;
3999 /* Allocate memory for the matrices */
4000 object->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4001 object->view_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4002 object->proj_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4003 memcpy(object->world_mat, id_mat, 16 * sizeof(float));
4004 memcpy(object->view_mat , id_mat, 16 * sizeof(float));
4005 memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
4006 for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
4007 object->tex_mat[tex_num] = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4008 memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
4009 object->tex_mat_is_identity[tex_num] = TRUE;
4012 /* Initialisation */
4013 TRACE(" setting current context\n");
4014 object->set_context(object);
4015 TRACE(" current context set\n");
4017 /* allocate the clipping planes */
4018 object->max_clipping_planes = opengl_device_caps.wMaxUserClipPlanes;
4019 object->clipping_planes = (d3d7clippingplane*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
4021 glHint(GL_FOG_HINT,GL_NICEST);
4023 /* Initialize the various GL contexts to be in sync with what we store locally */
4024 glClearDepth(0.0);
4025 glClearStencil(0);
4026 glClearColor(0.0, 0.0, 0.0, 0.0);
4027 glDepthMask(GL_TRUE);
4028 gl_object->depth_mask = TRUE;
4029 glEnable(GL_DEPTH_TEST);
4030 gl_object->depth_test = TRUE;
4031 glDisable(GL_ALPHA_TEST);
4032 glDisable(GL_STENCIL_TEST);
4033 glDisable(GL_CULL_FACE);
4034 glDisable(GL_LIGHTING);
4035 glDisable(GL_BLEND);
4036 glDisable(GL_FOG);
4037 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4038 gl_object->current_tex_env = GL_REPLACE;
4039 gl_object->current_active_tex_unit = GL_TEXTURE0_WINE;
4040 if (GL_extensions.glActiveTexture != NULL) {
4041 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
4043 gl_object->current_alpha_test_ref = 0.0;
4044 gl_object->current_alpha_test_func = GL_ALWAYS;
4045 glAlphaFunc(GL_ALWAYS, 0.0);
4047 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4048 glDrawBuffer(buffer);
4049 glReadBuffer(buffer);
4050 /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
4051 LEAVE_GL();
4053 gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
4054 gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
4056 /* fill_device_capabilities(d3d->ddraw); */
4058 ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
4059 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
4060 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
4061 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
4063 *obj = object;
4065 TRACE(" creating implementation at %p.\n", *obj);
4067 /* And finally warn D3D that this device is now present */
4068 object->d3d->d3d_added_device(object->d3d, object);
4070 /* FIXME: Should handle other versions than just 7 */
4071 InitDefaultStateBlock(&object->state_block, 7);
4072 /* Apply default render state and texture stage state values */
4073 apply_render_state(object, &object->state_block);
4074 apply_texture_state(object);
4076 /* And fill the fog table with the default fog value */
4077 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4079 return DD_OK;
4082 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4084 pc->dwSize = sizeof(*pc);
4085 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4086 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4087 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4088 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4089 D3DPRASTERCAPS_ZFOG;
4090 if (GL_extensions.mipmap_lodbias) {
4091 pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4093 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4094 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4095 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4096 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4097 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4098 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4099 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4100 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4101 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4102 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4103 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4104 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4105 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4106 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4107 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4108 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4109 D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4110 D3DPTFILTERCAPS_MIPFPOINT;
4111 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4112 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4113 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4114 if (GL_extensions.mirrored_repeat) {
4115 pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4117 pc->dwStippleWidth = 32;
4118 pc->dwStippleHeight = 32;
4121 static void fill_caps(void)
4123 GLint max_clip_planes;
4124 GLint depth_bits;
4126 /* Fill first all the fields with default values which will be overriden later on with
4127 correct ones from the GL code
4129 opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4130 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4131 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4132 /* D3D 7 capabilities */
4133 D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4134 fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4135 fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4136 opengl_device_caps.dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
4137 opengl_device_caps.dwMinTextureWidth = 1;
4138 opengl_device_caps.dwMinTextureHeight = 1;
4139 opengl_device_caps.dwMaxTextureWidth = 1024;
4140 opengl_device_caps.dwMaxTextureHeight = 1024;
4141 opengl_device_caps.dwMaxTextureRepeat = 16;
4142 opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4143 opengl_device_caps.dwMaxAnisotropy = 0;
4144 opengl_device_caps.dvGuardBandLeft = 0.0;
4145 opengl_device_caps.dvGuardBandRight = 0.0;
4146 opengl_device_caps.dvGuardBandTop = 0.0;
4147 opengl_device_caps.dvGuardBandBottom = 0.0;
4148 opengl_device_caps.dvExtentsAdjust = 0.0;
4149 opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4150 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4151 opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4152 D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4153 D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4154 if (GL_extensions.max_texture_units != 0) {
4155 opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4156 opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4157 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4158 } else {
4159 opengl_device_caps.wMaxTextureBlendStages = 1;
4160 opengl_device_caps.wMaxSimultaneousTextures = 1;
4161 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4163 opengl_device_caps.dwMaxActiveLights = 16;
4164 opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4165 opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4166 opengl_device_caps.wMaxUserClipPlanes = 1;
4167 opengl_device_caps.wMaxVertexBlendMatrices = 0;
4168 opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4169 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4170 opengl_device_caps.dwReserved1 = 0;
4171 opengl_device_caps.dwReserved2 = 0;
4172 opengl_device_caps.dwReserved3 = 0;
4173 opengl_device_caps.dwReserved4 = 0;
4175 /* And now some GL overrides :-) */
4176 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4177 opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4178 opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4179 TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4181 glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4182 TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4184 glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4185 opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4186 TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4188 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4189 TRACE(": Z bits = %d\n", depth_bits);
4190 switch (depth_bits) {
4191 case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4192 case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4193 case 32:
4194 default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4198 BOOL
4199 d3ddevice_init_at_startup(void *gl_handle)
4201 XVisualInfo template;
4202 XVisualInfo *vis;
4203 HDC device_context;
4204 Display *display;
4205 Visual *visual;
4206 Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4207 XWindowAttributes win_attr;
4208 GLXContext gl_context;
4209 int num;
4210 const char *glExtensions;
4211 const char *glVersion;
4212 const char *glXExtensions = NULL;
4213 const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4214 int major, minor, patch, num_parsed;
4216 TRACE("Initializing GL...\n");
4218 if (!drawable)
4220 WARN("x11drv not loaded - D3D support disabled!\n");
4221 return FALSE;
4224 /* Get a default rendering context to have the 'caps' function query some info from GL */
4225 device_context = GetDC(0);
4226 display = get_display(device_context);
4227 ReleaseDC(0, device_context);
4229 ENTER_GL();
4230 if (XGetWindowAttributes(display, drawable, &win_attr)) {
4231 visual = win_attr.visual;
4232 } else {
4233 visual = DefaultVisual(display, DefaultScreen(display));
4235 template.visualid = XVisualIDFromVisual(visual);
4236 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4237 if (vis == NULL) {
4238 LEAVE_GL();
4239 WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4240 return FALSE;
4242 gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4244 if (gl_context == NULL) {
4245 LEAVE_GL();
4246 WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4247 return FALSE;
4249 if (glXMakeCurrent(display, drawable, gl_context) == False) {
4250 glXDestroyContext(display, gl_context);
4251 LEAVE_GL();
4252 WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4253 return FALSE;
4256 /* Then, query all extensions */
4257 glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4258 glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4259 glVersion = (const char *) glGetString(GL_VERSION);
4260 if (gl_handle != NULL) {
4261 pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4264 /* Parse the GL version string */
4265 num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4266 if (num_parsed == 1) {
4267 minor = 0;
4268 patch = 0;
4269 } else if (num_parsed == 2) {
4270 patch = 0;
4272 TRACE("GL version %d.%d.%d\n", major, minor, patch);
4274 /* And starts to fill the extension context properly */
4275 memset(&GL_extensions, 0, sizeof(GL_extensions));
4276 TRACE("GL supports following extensions used by Wine :\n");
4278 /* Mirrored Repeat extension :
4279 - GL_ARB_texture_mirrored_repeat
4280 - GL_IBM_texture_mirrored_repeat
4281 - GL >= 1.4
4283 if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4284 (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4285 (major > 1) ||
4286 ((major == 1) && (minor >= 4))) {
4287 TRACE(" - mirrored repeat\n");
4288 GL_extensions.mirrored_repeat = TRUE;
4291 /* Texture LOD Bias :
4292 - GL_EXT_texture_lod_bias
4294 if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4295 TRACE(" - texture lod bias\n");
4296 GL_extensions.mipmap_lodbias = TRUE;
4299 /* For all subsequent extensions, we need glXGetProcAddress */
4300 if (pglXGetProcAddressARB != NULL) {
4301 /* Multi-texturing :
4302 - GL_ARB_multitexture
4303 - GL >= 1.2.1
4305 if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4306 (major > 1) ||
4307 ((major == 1) && (minor > 2)) ||
4308 ((major == 1) && (minor == 2) && (patch >= 1))) {
4309 glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4310 TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4311 /* We query the ARB version to be the most portable we can... */
4312 GL_extensions.glActiveTexture = pglXGetProcAddressARB("glActiveTextureARB");
4313 GL_extensions.glMultiTexCoord2fv = pglXGetProcAddressARB("glMultiTexCoord2fv");
4314 GL_extensions.glClientActiveTexture = pglXGetProcAddressARB("glClientActiveTextureARB");
4317 if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4318 TRACE(" - S3TC compression supported\n");
4319 GL_extensions.s3tc_compressed_texture = TRUE;
4320 GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB("glCompressedTexImage2D");
4321 GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB("glCompressedTexSubImage2D");
4325 /* Fill the D3D capabilities according to what GL tells us... */
4326 fill_caps();
4328 /* And frees this now-useless context */
4329 glXMakeCurrent(display, None, NULL);
4330 glXDestroyContext(display, gl_context);
4331 LEAVE_GL();
4333 return TRUE;