Get rid of the no longer used ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
[wine/multimedia.git] / dlls / ddraw / d3ddevice / mesa.c
blob755e28849917314aeb9f1238734707f06e29b8ba
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;
385 TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, This->ref);
386 if (!--(This->ref)) {
387 int i;
388 IDirectDrawSurfaceImpl *surface = This->surface, *surf;
390 /* Release texture associated with the device */
391 for (i = 0; i < MAX_TEXTURES; i++) {
392 if (This->current_texture[i] != NULL)
393 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
394 HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
397 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
398 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
399 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
400 surf->aux_ctx = NULL;
401 surf->aux_data = NULL;
402 surf->aux_flip = NULL;
403 break;
406 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
407 IDirectDrawSurfaceImpl *surf2;
408 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
409 for (; surf2 != NULL; surf2 = surf2->next_attached) {
410 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
411 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
412 /* Override the Lock / Unlock function for all these surfaces */
413 surf2->lock_update = surf2->lock_update_prev;
414 surf2->unlock_update = surf2->unlock_update_prev;
415 /* And install also the blt / bltfast overrides */
416 surf2->aux_blt = NULL;
417 surf2->aux_bltfast = NULL;
419 surf2->d3ddevice = NULL;
423 /* And warn the D3D object that this device is no longer active... */
424 This->d3d->d3d_removed_device(This->d3d, This);
426 HeapFree(GetProcessHeap(), 0, This->world_mat);
427 HeapFree(GetProcessHeap(), 0, This->view_mat);
428 HeapFree(GetProcessHeap(), 0, This->proj_mat);
430 if (glThis->surface_ptr)
431 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
433 DeleteCriticalSection(&(This->crit));
435 ENTER_GL();
436 if (glThis->unlock_tex)
437 glDeleteTextures(1, &(glThis->unlock_tex));
438 glXDestroyContext(glThis->display, glThis->gl_context);
439 LEAVE_GL();
440 HeapFree(GetProcessHeap(), 0, This->clipping_planes);
442 HeapFree(GetProcessHeap(), 0, This);
443 return 0;
445 return This->ref;
448 HRESULT WINAPI
449 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
450 LPD3DDEVICEDESC lpD3DHWDevDesc,
451 LPD3DDEVICEDESC lpD3DHELDevDesc)
453 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
454 D3DDEVICEDESC desc;
455 DWORD dwSize;
457 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
459 fill_opengl_caps(&desc);
460 dwSize = lpD3DHWDevDesc->dwSize;
461 memset(lpD3DHWDevDesc, 0, dwSize);
462 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
464 dwSize = lpD3DHELDevDesc->dwSize;
465 memset(lpD3DHELDevDesc, 0, dwSize);
466 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
468 TRACE(" returning caps : (no dump function yet)\n");
470 return DD_OK;
473 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
474 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
475 LPVOID context)
477 DDSURFACEDESC sdesc;
478 LPDDPIXELFORMAT pformat;
480 /* Do the texture enumeration */
481 sdesc.dwSize = sizeof(DDSURFACEDESC);
482 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
483 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
484 pformat = &(sdesc.ddpfPixelFormat);
485 pformat->dwSize = sizeof(DDPIXELFORMAT);
486 pformat->dwFourCC = 0;
488 TRACE("Enumerating GL_RGBA unpacked (32)\n");
489 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
490 pformat->u1.dwRGBBitCount = 32;
491 pformat->u2.dwRBitMask = 0x00FF0000;
492 pformat->u3.dwGBitMask = 0x0000FF00;
493 pformat->u4.dwBBitMask = 0x000000FF;
494 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
495 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
496 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
498 TRACE("Enumerating GL_RGB unpacked (32)\n");
499 pformat->dwFlags = DDPF_RGB;
500 pformat->u1.dwRGBBitCount = 32;
501 pformat->u2.dwRBitMask = 0x00FF0000;
502 pformat->u3.dwGBitMask = 0x0000FF00;
503 pformat->u4.dwBBitMask = 0x000000FF;
504 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
505 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
506 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
508 TRACE("Enumerating GL_RGB unpacked (24)\n");
509 pformat->dwFlags = DDPF_RGB;
510 pformat->u1.dwRGBBitCount = 24;
511 pformat->u2.dwRBitMask = 0x00FF0000;
512 pformat->u3.dwGBitMask = 0x0000FF00;
513 pformat->u4.dwBBitMask = 0x000000FF;
514 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
515 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
516 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
518 /* Note : even if this is an 'emulated' texture format, it needs to be first
519 as some dumb applications seem to rely on that. */
520 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
521 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
522 pformat->u1.dwRGBBitCount = 16;
523 pformat->u2.dwRBitMask = 0x00007C00;
524 pformat->u3.dwGBitMask = 0x000003E0;
525 pformat->u4.dwBBitMask = 0x0000001F;
526 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
527 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
528 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
530 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
531 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
532 pformat->u1.dwRGBBitCount = 16;
533 pformat->u2.dwRBitMask = 0x00000F00;
534 pformat->u3.dwGBitMask = 0x000000F0;
535 pformat->u4.dwBBitMask = 0x0000000F;
536 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
537 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
538 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
540 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
541 pformat->dwFlags = DDPF_RGB;
542 pformat->u1.dwRGBBitCount = 16;
543 pformat->u2.dwRBitMask = 0x0000F800;
544 pformat->u3.dwGBitMask = 0x000007E0;
545 pformat->u4.dwBBitMask = 0x0000001F;
546 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
547 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
548 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
550 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
551 pformat->dwFlags = DDPF_RGB;
552 pformat->u1.dwRGBBitCount = 16;
553 pformat->u2.dwRBitMask = 0x00007C00;
554 pformat->u3.dwGBitMask = 0x000003E0;
555 pformat->u4.dwBBitMask = 0x0000001F;
556 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
557 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
558 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
560 #if 0
561 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
562 find enumerated, others the last one. And both want to have the ARGB one.
564 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
566 /* See argument about the RGBA format for 'packed' texture formats */
567 TRACE("Enumerating GL_RGBA unpacked (32)\n");
568 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
569 pformat->u1.dwRGBBitCount = 32;
570 pformat->u2.dwRBitMask = 0xFF000000;
571 pformat->u3.dwGBitMask = 0x00FF0000;
572 pformat->u4.dwBBitMask = 0x0000FF00;
573 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
574 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
575 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
577 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
578 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
579 pformat->u1.dwRGBBitCount = 16;
580 pformat->u2.dwRBitMask = 0x0000F000;
581 pformat->u3.dwGBitMask = 0x00000F00;
582 pformat->u4.dwBBitMask = 0x000000F0;
583 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
584 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
585 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
587 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
588 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
589 pformat->u1.dwRGBBitCount = 16;
590 pformat->u2.dwRBitMask = 0x0000F800;
591 pformat->u3.dwGBitMask = 0x000007C0;
592 pformat->u4.dwBBitMask = 0x0000003E;
593 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
594 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
595 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
596 #endif
598 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
599 pformat->dwFlags = DDPF_RGB;
600 pformat->u1.dwRGBBitCount = 8;
601 pformat->u2.dwRBitMask = 0x000000E0;
602 pformat->u3.dwGBitMask = 0x0000001C;
603 pformat->u4.dwBBitMask = 0x00000003;
604 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
605 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
606 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
608 TRACE("Enumerating Paletted (8)\n");
609 pformat->dwFlags = DDPF_PALETTEINDEXED8;
610 pformat->u1.dwRGBBitCount = 8;
611 pformat->u2.dwRBitMask = 0x00000000;
612 pformat->u3.dwGBitMask = 0x00000000;
613 pformat->u4.dwBBitMask = 0x00000000;
614 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
615 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
616 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
618 if (GL_extensions.s3tc_compressed_texture) {
619 TRACE("Enumerating DXT1\n");
620 pformat->dwFlags = DDPF_FOURCC;
621 pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
622 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
623 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
625 TRACE("Enumerating DXT3\n");
626 pformat->dwFlags = DDPF_FOURCC;
627 pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
628 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
629 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
631 TRACE("Enumerating DXT5\n");
632 pformat->dwFlags = DDPF_FOURCC;
633 pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
634 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
635 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
638 TRACE("End of enumeration\n");
639 return DD_OK;
643 HRESULT
644 d3ddevice_find(IDirectDrawImpl *d3d,
645 LPD3DFINDDEVICESEARCH lpD3DDFS,
646 LPD3DFINDDEVICERESULT lplpD3DDevice)
648 D3DDEVICEDESC desc;
650 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
651 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
652 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
653 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
655 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
656 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
657 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
658 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
659 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
660 TRACE(" no match for this GUID.\n");
661 return DDERR_INVALIDPARAMS;
665 /* Now return our own GUID */
666 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
667 fill_opengl_caps(&desc);
668 lplpD3DDevice->ddHwDesc = desc;
669 lplpD3DDevice->ddSwDesc = desc;
671 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
673 return D3D_OK;
676 HRESULT WINAPI
677 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
678 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
679 LPVOID lpArg)
681 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
682 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
683 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg);
686 HRESULT WINAPI
687 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
688 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
689 LPVOID lpArg)
691 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
692 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
693 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg);
696 HRESULT WINAPI
697 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
698 D3DRENDERSTATETYPE dwRenderStateType,
699 DWORD dwRenderState)
701 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
702 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
704 /* Call the render state functions */
705 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
706 set_render_state(This, dwRenderStateType, &This->state_block);
708 return DD_OK;
711 HRESULT WINAPI
712 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
713 D3DRENDERSTATETYPE dwRenderStateType,
714 LPDWORD lpdwRenderState)
716 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
717 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
719 /* Call the render state functions */
720 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
722 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
724 return DD_OK;
727 HRESULT WINAPI
728 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
729 D3DLIGHTSTATETYPE dwLightStateType,
730 LPDWORD lpdwLightState)
732 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
734 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
736 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
737 TRACE("Unexpected Light State Type\n");
738 return DDERR_INVALIDPARAMS;
741 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
742 *lpdwLightState = This->material;
743 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
744 *lpdwLightState = D3DCOLOR_RGB;
745 } else {
746 D3DRENDERSTATETYPE rs;
747 switch (dwLightStateType) {
748 case D3DLIGHTSTATE_AMBIENT: /* 2 */
749 rs = D3DRENDERSTATE_AMBIENT;
750 break;
751 case D3DLIGHTSTATE_FOGMODE: /* 4 */
752 rs = D3DRENDERSTATE_FOGVERTEXMODE;
753 break;
754 case D3DLIGHTSTATE_FOGSTART: /* 5 */
755 rs = D3DRENDERSTATE_FOGSTART;
756 break;
757 case D3DLIGHTSTATE_FOGEND: /* 6 */
758 rs = D3DRENDERSTATE_FOGEND;
759 break;
760 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
761 rs = D3DRENDERSTATE_FOGDENSITY;
762 break;
763 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
764 rs = D3DRENDERSTATE_COLORVERTEX;
765 break;
766 default:
767 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
768 return DDERR_INVALIDPARAMS;
771 IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
772 rs,lpdwLightState);
775 return DD_OK;
778 HRESULT WINAPI
779 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
780 D3DLIGHTSTATETYPE dwLightStateType,
781 DWORD dwLightState)
783 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
785 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
787 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
788 TRACE("Unexpected Light State Type\n");
789 return DDERR_INVALIDPARAMS;
792 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
793 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
795 if (mat != NULL) {
796 TRACE(" activating material %p.\n", mat);
797 mat->activate(mat);
798 } else {
799 FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
801 This->material = dwLightState;
802 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
803 switch (dwLightState) {
804 case D3DCOLOR_MONO:
805 ERR("DDCOLOR_MONO should not happen!\n");
806 break;
807 case D3DCOLOR_RGB:
808 /* We are already in this mode */
809 TRACE("Setting color model to RGB (no-op).\n");
810 break;
811 default:
812 ERR("Unknown color model!\n");
813 return DDERR_INVALIDPARAMS;
815 } else {
816 D3DRENDERSTATETYPE rs;
817 switch (dwLightStateType) {
818 case D3DLIGHTSTATE_AMBIENT: /* 2 */
819 rs = D3DRENDERSTATE_AMBIENT;
820 break;
821 case D3DLIGHTSTATE_FOGMODE: /* 4 */
822 rs = D3DRENDERSTATE_FOGVERTEXMODE;
823 break;
824 case D3DLIGHTSTATE_FOGSTART: /* 5 */
825 rs = D3DRENDERSTATE_FOGSTART;
826 break;
827 case D3DLIGHTSTATE_FOGEND: /* 6 */
828 rs = D3DRENDERSTATE_FOGEND;
829 break;
830 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
831 rs = D3DRENDERSTATE_FOGDENSITY;
832 break;
833 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
834 rs = D3DRENDERSTATE_COLORVERTEX;
835 break;
836 default:
837 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
838 return DDERR_INVALIDPARAMS;
841 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
842 rs,dwLightState);
845 return DD_OK;
848 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
850 switch (d3dpt) {
851 case D3DPT_POINTLIST:
852 TRACE(" primitive type is POINTS\n");
853 return GL_POINTS;
855 case D3DPT_LINELIST:
856 TRACE(" primitive type is LINES\n");
857 return GL_LINES;
859 case D3DPT_LINESTRIP:
860 TRACE(" primitive type is LINE_STRIP\n");
861 return GL_LINE_STRIP;
863 case D3DPT_TRIANGLELIST:
864 TRACE(" primitive type is TRIANGLES\n");
865 return GL_TRIANGLES;
867 case D3DPT_TRIANGLESTRIP:
868 TRACE(" primitive type is TRIANGLE_STRIP\n");
869 return GL_TRIANGLE_STRIP;
871 case D3DPT_TRIANGLEFAN:
872 TRACE(" primitive type is TRIANGLE_FAN\n");
873 return GL_TRIANGLE_FAN;
875 default:
876 FIXME("Unhandled primitive %08x\n", d3dpt);
877 return GL_POINTS;
881 /* This function calculate the Z coordinate from Zproj */
882 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
884 float a,b,c,d;
885 /* Assume that X = Y = 0 and W = 1 */
886 a = This->proj_mat->_33;
887 b = This->proj_mat->_34;
888 c = This->proj_mat->_43;
889 d = This->proj_mat->_44;
890 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
891 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
892 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
894 return (d*Zproj - c) / (a - b*Zproj);
897 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
898 int i;
900 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
902 for (i = 0; i < 3; i++) {
903 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
904 DWORD elt;
905 for (elt = 0; elt < 0x10000; elt++) {
906 /* We apply the fog transformation and cache the result */
907 DWORD fog_intensity = elt & 0xFF;
908 DWORD vertex_color = (elt >> 8) & 0xFF;
909 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
914 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
915 BOOLEAN vertex_transformed,
916 BOOLEAN vertex_lit) {
917 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
919 /* Puts GL in the correct lighting / transformation mode */
920 if ((vertex_transformed == FALSE) &&
921 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
922 /* Need to put the correct transformation again if we go from Transformed
923 vertices to non-transformed ones.
925 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
926 This->world_mat, This->view_mat, This->proj_mat);
927 glThis->transform_state = GL_TRANSFORM_NORMAL;
929 } else if ((vertex_transformed == TRUE) &&
930 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
931 /* Set our orthographic projection */
932 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
933 glThis->transform_state = GL_TRANSFORM_ORTHO;
934 d3ddevice_set_ortho(This);
938 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
939 if no fogging state change occurred */
940 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
941 if (vertex_transformed == TRUE) {
942 if (glThis->fogging != 0) {
943 glDisable(GL_FOG);
944 glThis->fogging = 0;
946 /* Now check if our fog_table still corresponds to the current vertex color.
947 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
948 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
949 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
950 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
951 /* We need to rebuild our fog table.... */
952 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
954 } else {
955 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
956 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
957 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
958 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
959 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
961 if (vertex_lit == FALSE) {
962 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
963 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
964 } else {
965 /* Special case of 'pixel fog' */
966 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
967 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
969 if (glThis->fogging == 0) {
970 glEnable(GL_FOG);
971 glThis->fogging = 1;
973 } else {
974 if (glThis->fogging != 0) {
975 glDisable(GL_FOG);
976 glThis->fogging = 0;
980 } else {
981 if (glThis->fogging != 0) {
982 glDisable(GL_FOG);
983 glThis->fogging = 0;
987 /* Handle the 'no-normal' case */
988 if ((vertex_lit == FALSE) && (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE)) {
989 if (glThis->lighting == 0) {
990 glEnable(GL_LIGHTING);
991 glThis->lighting = 1;
993 } else {
994 if (glThis->lighting != 0) {
995 glDisable(GL_LIGHTING);
996 glThis->lighting = 0;
1000 /* Handle the code for pre-vertex material properties */
1001 if (vertex_transformed == FALSE) {
1002 if ((This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1003 (This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1004 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1005 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1006 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1007 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1008 glEnable(GL_COLOR_MATERIAL);
1015 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1016 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1018 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1020 switch (d3dvt) {
1021 case D3DVT_VERTEX: {
1022 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1023 strided.position.dwStride = sizeof(D3DVERTEX);
1024 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1025 strided.normal.dwStride = sizeof(D3DVERTEX);
1026 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1027 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1028 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1029 } break;
1031 case D3DVT_LVERTEX: {
1032 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1033 strided.position.dwStride = sizeof(D3DLVERTEX);
1034 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1035 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1036 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1037 strided.specular.dwStride = sizeof(D3DLVERTEX);
1038 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1039 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1040 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1041 } break;
1043 case D3DVT_TLVERTEX: {
1044 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1045 strided.position.dwStride = sizeof(D3DTLVERTEX);
1046 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1047 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1048 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1049 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1050 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1051 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1052 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1053 } break;
1055 default:
1056 FIXME("Unhandled vertex type %08x\n", d3dvt);
1057 break;
1061 HRESULT WINAPI
1062 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1063 D3DPRIMITIVETYPE d3dptPrimitiveType,
1064 D3DVERTEXTYPE d3dvtVertexType,
1065 LPVOID lpvVertices,
1066 DWORD dwVertexCount,
1067 DWORD dwFlags)
1069 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1071 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1072 if (TRACE_ON(ddraw)) {
1073 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1076 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1078 return DD_OK;
1081 HRESULT WINAPI
1082 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1083 D3DPRIMITIVETYPE d3dptPrimitiveType,
1084 D3DVERTEXTYPE d3dvtVertexType,
1085 LPVOID lpvVertices,
1086 DWORD dwVertexCount,
1087 LPWORD dwIndices,
1088 DWORD dwIndexCount,
1089 DWORD dwFlags)
1091 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1092 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1093 if (TRACE_ON(ddraw)) {
1094 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1097 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1099 return DD_OK;
1102 HRESULT WINAPI
1103 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1104 LPD3DEXECUTEBUFFERDESC lpDesc,
1105 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1106 IUnknown* pUnkOuter)
1108 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1109 IDirect3DExecuteBufferImpl *ret;
1110 HRESULT ret_value;
1112 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1114 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1115 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1117 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1119 return ret_value;
1122 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1123 static BOOLEAN first = TRUE;
1124 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1125 int row;
1126 GLenum type;
1128 if (first == TRUE) {
1129 MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1130 first = FALSE;
1133 TRACE("flushing ZBuffer back to GL\n");
1135 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1136 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1137 d3ddevice_set_ortho(d3d_dev);
1140 glMatrixMode(GL_MODELVIEW);
1141 glLoadIdentity();
1143 if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1144 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1145 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1147 /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1148 in some drivers...
1150 switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1151 case 16: type = GL_UNSIGNED_SHORT; break;
1152 case 32: type = GL_UNSIGNED_INT; break;
1153 default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1156 for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1157 /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1158 glRasterPos2i(0, row + 1);
1159 glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1160 ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1163 restore_state:
1164 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1165 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1166 glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1167 if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1170 /* These are the various handler used in the generic path */
1171 inline static void handle_xyz(D3DVALUE *coords) {
1172 glVertex3fv(coords);
1174 inline static void handle_xyzrhw(D3DVALUE *coords) {
1175 if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1176 glVertex3fv(coords);
1177 else {
1178 GLfloat w = 1.0 / coords[3];
1180 glVertex4f(coords[0] * w,
1181 coords[1] * w,
1182 coords[2] * w,
1186 inline static void handle_normal(D3DVALUE *coords) {
1187 glNormal3fv(coords);
1190 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1191 if ((sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == TRUE) ||
1192 (sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1] == TRUE)) {
1193 glColor4ub((*color >> 16) & 0xFF,
1194 (*color >> 8) & 0xFF,
1195 (*color >> 0) & 0xFF,
1196 (*color >> 24) & 0xFF);
1197 } else {
1198 glColor3ub((*color >> 16) & 0xFF,
1199 (*color >> 8) & 0xFF,
1200 (*color >> 0) & 0xFF);
1204 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1205 glColor4ub((*color >> 16) & 0xFF,
1206 (*color >> 8) & 0xFF,
1207 (*color >> 0) & 0xFF,
1208 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1211 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1212 if ((lighted == FALSE) &&
1213 (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1214 (sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1215 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1216 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1217 handle_diffuse_base(sb, color);
1219 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1220 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1221 handle_diffuse_base(sb, color);
1223 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1224 (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
1225 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1226 handle_diffuse_base(sb, color);
1228 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1229 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1230 handle_diffuse_base(sb, color);
1232 } else {
1233 handle_diffuse_base(sb, color);
1237 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1238 if ((lighted == FALSE) &&
1239 (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1240 (sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1241 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1242 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1243 handle_specular_base(sb, color);
1245 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1246 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1247 handle_specular_base(sb, color);
1249 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1250 (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
1251 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1252 handle_specular_base(sb, color);
1254 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1255 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1256 handle_specular_base(sb, color);
1259 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1262 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1263 if (lighted == TRUE) {
1264 DWORD color = *color_d;
1265 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
1266 /* Special case where the specular value is used to do fogging */
1267 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1268 color &= 0xFF000000; /* Only keep the alpha component */
1269 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1270 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1271 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1273 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE) {
1274 /* Standard specular value in transformed mode. TODO */
1276 handle_diffuse_base(sb, &color);
1277 } else {
1278 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) {
1279 handle_diffuse(sb, color_d, FALSE);
1280 handle_specular(sb, color_s, FALSE);
1281 } else {
1282 /* In that case, only put the diffuse color... */
1283 handle_diffuse_base(sb, color_d);
1288 inline static void handle_texture(D3DVALUE *coords) {
1289 glTexCoord2fv(coords);
1291 inline static void handle_textures(D3DVALUE *coords, int tex_stage) {
1292 if (GL_extensions.glMultiTexCoord2fv) {
1293 GL_extensions.glMultiTexCoord2fv(GL_TEXTURE0_WINE + tex_stage, coords);
1294 } else {
1295 if (tex_stage == 0) glTexCoord2fv(coords);
1299 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1300 D3DPRIMITIVETYPE d3dptPrimitiveType,
1301 DWORD d3dvtVertexType,
1302 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1303 DWORD dwVertexCount,
1304 LPWORD dwIndices,
1305 DWORD dwIndexCount,
1306 DWORD dwFlags)
1308 BOOLEAN vertex_lighted = FALSE;
1309 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1310 int num_active_stages = 0;
1311 int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
1313 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1314 if (TRACE_ON(ddraw)) {
1315 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1318 /* This is to prevent 'thread contention' between a thread locking the device and another
1319 doing 3D display on it... */
1320 EnterCriticalSection(&(This->crit));
1322 ENTER_GL();
1323 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1324 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1326 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1328 if (This->current_zbuffer == NULL) {
1329 /* Search for an attached ZBuffer */
1330 static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1331 LPDIRECTDRAWSURFACE7 zbuf;
1332 HRESULT hr;
1334 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1335 (DDSCAPS2 *) &zbuf_caps, &zbuf);
1336 if (!FAILED(hr)) {
1337 This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1338 IDirectDrawSurface7_Release(zbuf);
1341 if (This->current_zbuffer != NULL) {
1342 if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1343 flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1347 if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1348 ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1349 vertex_lighted = TRUE;
1351 /* Compute the number of active texture stages and set the various texture parameters */
1352 num_active_stages = draw_primitive_handle_textures(This);
1354 /* And restore to handle '0' in the case we use glTexCoord calls */
1355 if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1356 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1357 glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1360 draw_primitive_handle_GL_state(This,
1361 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1362 vertex_lighted);
1364 /* First, see if we can use the OpenGL vertex arrays... This is very limited
1365 for now to some 'special' cases where we can do a direct mapping between D3D
1366 types and GL types.
1368 Note: in the future all calls will go through vertex arrays but the arrays
1369 will be generated by this function.
1371 Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1372 (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1373 which, as we are little indian, gives a B, G, R, A storage in memory.
1375 if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1376 ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1377 int tex_stage;
1378 TRACE(" using GL vertex arrays for performance !\n");
1379 /* First, the vertices (we are sure we have some :-) */
1380 glEnableClientState(GL_VERTEX_ARRAY);
1381 glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1382 /* Then the normals */
1383 if (d3dvtVertexType & D3DFVF_NORMAL) {
1384 glEnableClientState(GL_NORMAL_ARRAY);
1385 glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1387 /* Then the diffuse colour */
1388 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1389 glEnableClientState(GL_COLOR_ARRAY);
1390 glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1391 ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1393 /* Then the various textures */
1394 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1395 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1396 if (tex_index >= num_tex_index) {
1397 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1398 tex_index = num_tex_index - 1;
1400 if (GL_extensions.glClientActiveTexture) {
1401 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1403 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1404 glTexCoordPointer(2, GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1405 lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1407 if (dwIndices != NULL) {
1408 glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1409 } else {
1410 glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1412 glDisableClientState(GL_VERTEX_ARRAY);
1413 if (d3dvtVertexType & D3DFVF_NORMAL) {
1414 glDisableClientState(GL_NORMAL_ARRAY);
1416 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1417 glDisableClientState(GL_COLOR_ARRAY);
1419 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1420 if (GL_extensions.glClientActiveTexture) {
1421 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1423 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1425 } else {
1426 glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1428 /* Some fast paths first before the generic case.... */
1429 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1430 int index;
1432 for (index = 0; index < dwIndexCount; index++) {
1433 int i = (dwIndices == NULL) ? index : dwIndices[index];
1434 D3DVALUE *normal =
1435 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1436 D3DVALUE *tex_coord =
1437 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1438 D3DVALUE *position =
1439 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1441 handle_normal(normal);
1442 handle_texture(tex_coord);
1443 handle_xyz(position);
1445 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1446 position[0], position[1], position[2],
1447 normal[0], normal[1], normal[2],
1448 tex_coord[0], tex_coord[1]);
1450 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1451 int index;
1453 for (index = 0; index < dwIndexCount; index++) {
1454 int i = (dwIndices == NULL) ? index : dwIndices[index];
1455 DWORD *color_d =
1456 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1457 DWORD *color_s =
1458 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1459 D3DVALUE *tex_coord =
1460 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1461 D3DVALUE *position =
1462 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1464 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1465 handle_texture(tex_coord);
1466 handle_xyzrhw(position);
1468 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1469 position[0], position[1], position[2], position[3],
1470 (*color_d >> 16) & 0xFF,
1471 (*color_d >> 8) & 0xFF,
1472 (*color_d >> 0) & 0xFF,
1473 (*color_d >> 24) & 0xFF,
1474 (*color_s >> 16) & 0xFF,
1475 (*color_s >> 8) & 0xFF,
1476 (*color_s >> 0) & 0xFF,
1477 (*color_s >> 24) & 0xFF,
1478 tex_coord[0], tex_coord[1]);
1480 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1481 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1482 /* This is the 'slow path' but that should support all possible vertex formats out there...
1483 Note that people should write a fast path for all vertex formats out there...
1485 int index;
1486 static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
1488 for (index = 0; index < dwIndexCount; index++) {
1489 int i = (dwIndices == NULL) ? index : dwIndices[index];
1490 int tex_stage;
1492 if (d3dvtVertexType & D3DFVF_NORMAL) {
1493 D3DVALUE *normal =
1494 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1495 handle_normal(normal);
1497 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1498 DWORD *color_d =
1499 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1500 DWORD *color_s =
1501 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1502 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1503 } else {
1504 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1505 DWORD *color_s =
1506 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1507 handle_specular(&(This->state_block), color_s, vertex_lighted);
1508 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1509 DWORD *color_d =
1510 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1511 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1515 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1516 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1517 if (tex_index >= num_tex_index) {
1518 handle_textures((D3DVALUE *) no_index, tex_stage);
1519 } else {
1520 D3DVALUE *tex_coord =
1521 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1522 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1523 handle_textures(tex_coord, tex_stage);
1527 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1528 D3DVALUE *position =
1529 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1530 handle_xyz(position);
1531 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1532 D3DVALUE *position =
1533 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1534 handle_xyzrhw(position);
1537 if (TRACE_ON(ddraw_geom)) {
1538 int tex_index;
1540 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1541 D3DVALUE *position =
1542 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1543 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1544 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1545 D3DVALUE *position =
1546 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1547 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1549 if (d3dvtVertexType & D3DFVF_NORMAL) {
1550 D3DVALUE *normal =
1551 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1552 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1554 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1555 DWORD *color_d =
1556 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1557 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1558 (*color_d >> 16) & 0xFF,
1559 (*color_d >> 8) & 0xFF,
1560 (*color_d >> 0) & 0xFF,
1561 (*color_d >> 24) & 0xFF);
1563 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1564 DWORD *color_s =
1565 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1566 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1567 (*color_s >> 16) & 0xFF,
1568 (*color_s >> 8) & 0xFF,
1569 (*color_s >> 0) & 0xFF,
1570 (*color_s >> 24) & 0xFF);
1572 for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
1573 D3DVALUE *tex_coord =
1574 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1575 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1576 TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
1578 TRACE_(ddraw_geom)("\n");
1581 } else {
1582 ERR(" matrix weighting not handled yet....\n");
1585 glEnd();
1588 /* Whatever the case, disable the color material stuff */
1589 glDisable(GL_COLOR_MATERIAL);
1591 LEAVE_GL();
1592 TRACE("End\n");
1594 LeaveCriticalSection(&(This->crit));
1597 HRESULT WINAPI
1598 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1599 D3DPRIMITIVETYPE d3dptPrimitiveType,
1600 DWORD d3dvtVertexType,
1601 LPVOID lpvVertices,
1602 DWORD dwVertexCount,
1603 DWORD dwFlags)
1605 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1606 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1608 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1609 if (TRACE_ON(ddraw)) {
1610 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1613 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1614 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1616 return DD_OK;
1619 HRESULT WINAPI
1620 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1621 D3DPRIMITIVETYPE d3dptPrimitiveType,
1622 DWORD d3dvtVertexType,
1623 LPVOID lpvVertices,
1624 DWORD dwVertexCount,
1625 LPWORD dwIndices,
1626 DWORD dwIndexCount,
1627 DWORD dwFlags)
1629 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1630 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1632 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1633 if (TRACE_ON(ddraw)) {
1634 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1637 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1638 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1640 return DD_OK;
1643 HRESULT WINAPI
1644 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1645 D3DPRIMITIVETYPE d3dptPrimitiveType,
1646 DWORD dwVertexType,
1647 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1648 DWORD dwVertexCount,
1649 DWORD dwFlags)
1651 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1653 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1654 if (TRACE_ON(ddraw)) {
1655 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1657 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1659 return DD_OK;
1662 HRESULT WINAPI
1663 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1664 D3DPRIMITIVETYPE d3dptPrimitiveType,
1665 DWORD dwVertexType,
1666 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1667 DWORD dwVertexCount,
1668 LPWORD lpIndex,
1669 DWORD dwIndexCount,
1670 DWORD dwFlags)
1672 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1674 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1675 if (TRACE_ON(ddraw)) {
1676 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1679 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1681 return DD_OK;
1684 HRESULT WINAPI
1685 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1686 D3DPRIMITIVETYPE d3dptPrimitiveType,
1687 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1688 DWORD dwStartVertex,
1689 DWORD dwNumVertices,
1690 DWORD dwFlags)
1692 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1693 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1694 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1696 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1697 if (TRACE_ON(ddraw)) {
1698 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1701 if (vb_impl->processed == TRUE) {
1702 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1703 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1705 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1706 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1707 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1709 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1710 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1712 } else {
1713 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1714 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1717 return DD_OK;
1720 HRESULT WINAPI
1721 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1722 D3DPRIMITIVETYPE d3dptPrimitiveType,
1723 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1724 DWORD dwStartVertex,
1725 DWORD dwNumVertices,
1726 LPWORD lpwIndices,
1727 DWORD dwIndexCount,
1728 DWORD dwFlags)
1730 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1731 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1732 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1734 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1735 if (TRACE_ON(ddraw)) {
1736 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1739 if (vb_impl->processed == TRUE) {
1740 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1741 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1743 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1744 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1745 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1747 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1748 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1750 } else {
1751 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1752 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1755 return DD_OK;
1758 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1759 static BOOLEAN
1760 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1762 BOOLEAN is_complement = FALSE;
1763 BOOLEAN is_alpha_replicate = FALSE;
1764 BOOLEAN handled = TRUE;
1765 GLenum src;
1766 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1767 int num;
1769 if (is_color) {
1770 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1771 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1772 else {
1773 handled = FALSE;
1774 num = 0;
1776 if (tex_op == D3DTOP_SELECTARG2) {
1777 num = 1 - num;
1779 } else {
1780 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1781 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1782 else {
1783 handled = FALSE;
1784 num = 0;
1786 if (tex_op == D3DTOP_SELECTARG2) {
1787 num = 1 - num;
1791 if (dwState & D3DTA_COMPLEMENT) {
1792 is_complement = TRUE;
1794 if (dwState & D3DTA_ALPHAREPLICATE) {
1795 is_alpha_replicate = TRUE;
1797 dwState &= D3DTA_SELECTMASK;
1798 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1799 dwState = D3DTA_DIFFUSE;
1802 switch (dwState) {
1803 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1804 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1805 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1806 case D3DTA_TFACTOR: {
1807 /* Get the constant value from the current rendering state */
1808 GLfloat color[4];
1809 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1811 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1812 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1813 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1814 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1815 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1817 src = GL_CONSTANT_EXT;
1818 } break;
1819 default: src = GL_TEXTURE; handled = FALSE; break;
1822 if (is_color) {
1823 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1824 if (is_alpha_replicate) {
1825 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1826 } else {
1827 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1829 } else {
1830 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1831 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1834 return handled;
1837 HRESULT WINAPI
1838 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1839 DWORD dwStage,
1840 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1841 DWORD dwState)
1843 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1844 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1845 const char *type;
1846 DWORD prev_state;
1847 GLenum unit;
1849 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1851 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1852 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1853 return DD_OK;
1856 unit = GL_TEXTURE0_WINE + dwStage;
1857 if (unit != glThis->current_active_tex_unit) {
1858 GL_extensions.glActiveTexture(unit);
1859 glThis->current_active_tex_unit = unit;
1862 switch (d3dTexStageStateType) {
1863 #define GEN_CASE(a) case a: type = #a; break
1864 GEN_CASE(D3DTSS_COLOROP);
1865 GEN_CASE(D3DTSS_COLORARG1);
1866 GEN_CASE(D3DTSS_COLORARG2);
1867 GEN_CASE(D3DTSS_ALPHAOP);
1868 GEN_CASE(D3DTSS_ALPHAARG1);
1869 GEN_CASE(D3DTSS_ALPHAARG2);
1870 GEN_CASE(D3DTSS_BUMPENVMAT00);
1871 GEN_CASE(D3DTSS_BUMPENVMAT01);
1872 GEN_CASE(D3DTSS_BUMPENVMAT10);
1873 GEN_CASE(D3DTSS_BUMPENVMAT11);
1874 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1875 GEN_CASE(D3DTSS_ADDRESS);
1876 GEN_CASE(D3DTSS_ADDRESSU);
1877 GEN_CASE(D3DTSS_ADDRESSV);
1878 GEN_CASE(D3DTSS_BORDERCOLOR);
1879 GEN_CASE(D3DTSS_MAGFILTER);
1880 GEN_CASE(D3DTSS_MINFILTER);
1881 GEN_CASE(D3DTSS_MIPFILTER);
1882 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1883 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1884 GEN_CASE(D3DTSS_MAXANISOTROPY);
1885 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1886 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1887 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1888 #undef GEN_CASE
1889 default: type = "UNKNOWN";
1892 /* Store the values in the state array */
1893 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1894 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1895 /* Some special cases when one state modifies more than one... */
1896 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1897 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1898 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1901 ENTER_GL();
1903 switch (d3dTexStageStateType) {
1904 case D3DTSS_MINFILTER:
1905 case D3DTSS_MIPFILTER:
1906 if (TRACE_ON(ddraw)) {
1907 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1908 switch ((D3DTEXTUREMINFILTER) dwState) {
1909 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1910 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1911 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1913 } else {
1914 switch ((D3DTEXTUREMIPFILTER) dwState) {
1915 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1916 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1917 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1918 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1922 break;
1924 case D3DTSS_MAGFILTER:
1925 if (TRACE_ON(ddraw)) {
1926 switch ((D3DTEXTUREMAGFILTER) dwState) {
1927 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1928 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1929 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1932 break;
1934 case D3DTSS_ADDRESS:
1935 case D3DTSS_ADDRESSU:
1936 case D3DTSS_ADDRESSV: {
1937 switch ((D3DTEXTUREADDRESS) dwState) {
1938 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1939 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1940 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1941 case D3DTADDRESS_MIRROR:
1942 if (GL_extensions.mirrored_repeat == TRUE) {
1943 TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1944 } else {
1945 FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1947 break;
1948 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1950 } break;
1952 case D3DTSS_ALPHAOP:
1953 case D3DTSS_COLOROP: {
1954 int scale = 1;
1955 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1956 const char *value;
1957 int handled = 1;
1959 switch (dwState) {
1960 #define GEN_CASE(a) case a: value = #a; break
1961 GEN_CASE(D3DTOP_DISABLE);
1962 GEN_CASE(D3DTOP_SELECTARG1);
1963 GEN_CASE(D3DTOP_SELECTARG2);
1964 GEN_CASE(D3DTOP_MODULATE);
1965 GEN_CASE(D3DTOP_MODULATE2X);
1966 GEN_CASE(D3DTOP_MODULATE4X);
1967 GEN_CASE(D3DTOP_ADD);
1968 GEN_CASE(D3DTOP_ADDSIGNED);
1969 GEN_CASE(D3DTOP_ADDSIGNED2X);
1970 GEN_CASE(D3DTOP_SUBTRACT);
1971 GEN_CASE(D3DTOP_ADDSMOOTH);
1972 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1973 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
1974 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
1975 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
1976 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
1977 GEN_CASE(D3DTOP_PREMODULATE);
1978 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
1979 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
1980 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
1981 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
1982 GEN_CASE(D3DTOP_BUMPENVMAP);
1983 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
1984 GEN_CASE(D3DTOP_DOTPRODUCT3);
1985 GEN_CASE(D3DTOP_FORCE_DWORD);
1986 #undef GEN_CASE
1987 default: value = "UNKNOWN";
1990 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
1991 glDisable(GL_TEXTURE_2D);
1992 TRACE(" disabling 2D texturing.\n");
1993 } else {
1994 /* Re-enable texturing only if COLOROP was not already disabled... */
1995 if ((glThis->current_bound_texture[dwStage] != NULL) &&
1996 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
1997 glEnable(GL_TEXTURE_2D);
1998 TRACE(" enabling 2D texturing.\n");
2001 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2002 if ((dwState != D3DTOP_DISABLE) &&
2003 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2004 if (glThis->current_tex_env != GL_COMBINE_EXT) {
2005 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2006 glThis->current_tex_env = GL_COMBINE_EXT;
2010 /* Now set up the operand correctly */
2011 switch (dwState) {
2012 case D3DTOP_DISABLE:
2013 /* Contrary to the docs, alpha can be disabled when colorop is enabled
2014 and it works, so ignore this op */
2015 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2016 break;
2018 case D3DTOP_SELECTARG1:
2019 case D3DTOP_SELECTARG2:
2020 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2021 break;
2023 case D3DTOP_MODULATE4X:
2024 scale = scale * 2; /* Drop through */
2025 case D3DTOP_MODULATE2X:
2026 scale = scale * 2; /* Drop through */
2027 case D3DTOP_MODULATE:
2028 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2029 break;
2031 case D3DTOP_ADD:
2032 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2033 break;
2035 case D3DTOP_ADDSIGNED2X:
2036 scale = scale * 2; /* Drop through */
2037 case D3DTOP_ADDSIGNED:
2038 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2039 break;
2041 /* For the four blending modes, use the Arg2 parameter */
2042 case D3DTOP_BLENDDIFFUSEALPHA:
2043 case D3DTOP_BLENDTEXTUREALPHA:
2044 case D3DTOP_BLENDFACTORALPHA:
2045 case D3DTOP_BLENDCURRENTALPHA: {
2046 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2048 switch (dwState) {
2049 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2050 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2051 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
2052 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2055 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2056 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2057 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2058 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2059 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2060 } break;
2062 default:
2063 handled = FALSE;
2064 break;
2068 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2069 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2070 /* Switch the arguments if needed... */
2071 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2072 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2073 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2074 dwState);
2075 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2076 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2077 dwState);
2078 } else {
2079 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2080 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2081 dwState);
2082 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2083 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2084 dwState);
2088 if (handled) {
2089 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2090 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2091 } else {
2092 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2094 TRACE(" Stage type is : %s => %s\n", type, value);
2095 } else {
2096 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2098 } break;
2100 case D3DTSS_COLORARG1:
2101 case D3DTSS_COLORARG2:
2102 case D3DTSS_ALPHAARG1:
2103 case D3DTSS_ALPHAARG2: {
2104 const char *value, *value_comp = "", *value_alpha = "";
2105 BOOLEAN handled;
2106 D3DTEXTUREOP tex_op;
2108 switch (dwState & D3DTA_SELECTMASK) {
2109 #define GEN_CASE(a) case a: value = #a; break
2110 GEN_CASE(D3DTA_DIFFUSE);
2111 GEN_CASE(D3DTA_CURRENT);
2112 GEN_CASE(D3DTA_TEXTURE);
2113 GEN_CASE(D3DTA_TFACTOR);
2114 GEN_CASE(D3DTA_SPECULAR);
2115 #undef GEN_CASE
2116 default: value = "UNKNOWN";
2118 if (dwState & D3DTA_COMPLEMENT) {
2119 value_comp = " | D3DTA_COMPLEMENT";
2121 if (dwState & D3DTA_ALPHAREPLICATE) {
2122 value_alpha = " | D3DTA_ALPHAREPLICATE";
2125 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2126 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2127 } else {
2128 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2131 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2133 if (handled) {
2134 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2135 } else {
2136 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2138 } break;
2140 case D3DTSS_MIPMAPLODBIAS: {
2141 D3DVALUE value = *((D3DVALUE *) &dwState);
2142 BOOLEAN handled = TRUE;
2144 if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2145 handled = FALSE;
2147 if (handled) {
2148 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2149 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2150 } else {
2151 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2153 } break;
2155 case D3DTSS_MAXMIPLEVEL:
2156 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2157 break;
2159 case D3DTSS_BORDERCOLOR:
2160 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2161 ((dwState >> 16) & 0xFF),
2162 ((dwState >> 8) & 0xFF),
2163 ((dwState >> 0) & 0xFF),
2164 ((dwState >> 24) & 0xFF));
2165 break;
2167 case D3DTSS_TEXCOORDINDEX: {
2168 BOOLEAN handled = TRUE;
2169 const char *value;
2171 switch (dwState & 0xFFFF0000) {
2172 #define GEN_CASE(a) case a: value = #a; break
2173 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2174 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2175 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2176 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2177 #undef GEN_CASE
2178 default: value = "UNKNOWN";
2180 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2181 handled = FALSE;
2183 if (handled) {
2184 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2185 } else {
2186 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2188 } break;
2190 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2191 const char *projected = "", *value;
2192 BOOLEAN handled = TRUE;
2193 switch (dwState & 0xFF) {
2194 #define GEN_CASE(a) case a: value = #a; break
2195 GEN_CASE(D3DTTFF_DISABLE);
2196 GEN_CASE(D3DTTFF_COUNT1);
2197 GEN_CASE(D3DTTFF_COUNT2);
2198 GEN_CASE(D3DTTFF_COUNT3);
2199 GEN_CASE(D3DTTFF_COUNT4);
2200 #undef GEN_CASE
2201 default: value = "UNKNOWN";
2203 if (dwState & D3DTTFF_PROJECTED) {
2204 projected = " | D3DTTFF_PROJECTED";
2205 handled = FALSE;
2208 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2209 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2212 if (handled == TRUE) {
2213 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2214 } else {
2215 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2217 } break;
2219 default:
2220 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2221 break;
2224 LEAVE_GL();
2226 return DD_OK;
2229 static DWORD
2230 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2232 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2233 DWORD stage;
2234 BOOLEAN enable_colorkey = FALSE;
2236 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2237 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2238 GLenum unit;
2240 /* If this stage is disabled, no need to go further... */
2241 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2242 break;
2244 /* First check if we need to bind any other texture for this stage */
2245 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2246 if (This->current_texture[stage] == NULL) {
2247 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2249 unit = GL_TEXTURE0_WINE + stage;
2250 if (unit != glThis->current_active_tex_unit) {
2251 GL_extensions.glActiveTexture(unit);
2252 glThis->current_active_tex_unit = unit;
2254 glBindTexture(GL_TEXTURE_2D, 0);
2255 glDisable(GL_TEXTURE_2D);
2256 } else {
2257 GLenum tex_name = ((IDirect3DTextureGLImpl *) surf_ptr->tex_private)->tex_name;
2259 unit = GL_TEXTURE0_WINE + stage;
2260 if (unit != glThis->current_active_tex_unit) {
2261 GL_extensions.glActiveTexture(unit);
2262 glThis->current_active_tex_unit = unit;
2265 if (glThis->current_bound_texture[stage] == NULL) {
2266 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2267 TRACE(" enabling 2D texturing and");
2268 glEnable(GL_TEXTURE_2D);
2271 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2272 glBindTexture(GL_TEXTURE_2D, tex_name);
2275 glThis->current_bound_texture[stage] = This->current_texture[stage];
2276 } else {
2277 if (glThis->current_bound_texture[stage] == NULL) {
2278 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2279 } else {
2280 TRACE(" using already bound texture id %d for stage %ld.\n",
2281 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2285 /* If no texure valid for this stage, go out of the loop */
2286 if (This->current_texture[stage] == NULL) break;
2288 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2289 This will also update the various texture parameters if needed.
2291 gltex_upload_texture(surf_ptr, This, stage);
2293 /* And finally check for color-keying (only on first stage) */
2294 if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2295 if (stage == 0) {
2296 enable_colorkey = TRUE;
2297 } else {
2298 static BOOL warn = FALSE;
2299 if (warn == FALSE) {
2300 warn = TRUE;
2301 WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2304 } else {
2305 if (stage == 0) {
2306 enable_colorkey = FALSE;
2311 /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2312 if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2313 (glThis->version == 1)) &&
2314 (enable_colorkey)) {
2315 TRACE(" colorkey activated.\n");
2317 if (glThis->alpha_test == FALSE) {
2318 glEnable(GL_ALPHA_TEST);
2319 glThis->alpha_test = TRUE;
2321 if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2322 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == TRUE) {
2323 static BOOL warn = FALSE;
2324 if (warn == FALSE) {
2325 warn = TRUE;
2326 WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2329 glThis->current_alpha_test_func = GL_NOTEQUAL;
2330 glThis->current_alpha_test_ref = 0.0;
2331 glAlphaFunc(GL_NOTEQUAL, 0.0);
2333 /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2334 Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2335 } else {
2336 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2337 glDisable(GL_ALPHA_TEST);
2338 glThis->alpha_test = FALSE;
2340 /* Maybe we should restore here the application-given alpha test states ? */
2343 return stage;
2346 HRESULT WINAPI
2347 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2348 DWORD dwStage,
2349 LPDIRECTDRAWSURFACE7 lpTexture2)
2351 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2353 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2355 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2356 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2357 if (lpTexture2 != NULL) {
2358 WARN(" setting a texture to a non-supported texture stage !\n");
2360 return DD_OK;
2363 if (This->current_texture[dwStage] != NULL) {
2364 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2367 if (lpTexture2 == NULL) {
2368 This->current_texture[dwStage] = NULL;
2369 } else {
2370 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2371 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2372 This->current_texture[dwStage] = tex_impl;
2375 return DD_OK;
2378 HRESULT WINAPI
2379 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2380 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2382 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2383 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2385 fill_opengl_caps_7(lpD3DHELDevDesc);
2387 TRACE(" returning caps : no dump function yet.\n");
2389 return DD_OK;
2392 HRESULT WINAPI
2393 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2394 LPD3DMATERIAL7 lpMat)
2396 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2397 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2399 if (TRACE_ON(ddraw)) {
2400 TRACE(" material is : \n");
2401 dump_D3DMATERIAL7(lpMat);
2404 This->current_material = *lpMat;
2406 ENTER_GL();
2407 glMaterialfv(GL_FRONT_AND_BACK,
2408 GL_DIFFUSE,
2409 (float *) &(This->current_material.u.diffuse));
2410 glMaterialfv(GL_FRONT_AND_BACK,
2411 GL_AMBIENT,
2412 (float *) &(This->current_material.u1.ambient));
2413 glMaterialfv(GL_FRONT_AND_BACK,
2414 GL_SPECULAR,
2415 (float *) &(This->current_material.u2.specular));
2416 glMaterialfv(GL_FRONT_AND_BACK,
2417 GL_EMISSION,
2418 (float *) &(This->current_material.u3.emissive));
2419 glMaterialf(GL_FRONT_AND_BACK,
2420 GL_SHININESS,
2421 This->current_material.u4.power); /* Not sure about this... */
2422 LEAVE_GL();
2424 return DD_OK;
2428 HRESULT WINAPI
2429 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2430 DWORD dwLightIndex,
2431 LPD3DLIGHT7 lpLight)
2433 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2434 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2435 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2437 if (TRACE_ON(ddraw)) {
2438 TRACE(" setting light : \n");
2439 dump_D3DLIGHT7(lpLight);
2442 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2443 This->set_lights |= 0x00000001 << dwLightIndex;
2444 This->light_parameters[dwLightIndex] = *lpLight;
2446 /* Some checks to print out nice warnings :-) */
2447 switch (lpLight->dltType) {
2448 case D3DLIGHT_DIRECTIONAL:
2449 case D3DLIGHT_POINT:
2450 /* These are handled properly... */
2451 break;
2453 case D3DLIGHT_SPOT:
2454 if ((lpLight->dvTheta != 0.0) ||
2455 (lpLight->dvTheta != lpLight->dvPhi)) {
2456 ERR("dvTheta not fully supported yet !\n");
2458 break;
2460 default:
2461 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2464 /* This will force the Light setting on next drawing of primitives */
2465 glThis->transform_state = GL_TRANSFORM_NONE;
2467 return DD_OK;
2470 HRESULT WINAPI
2471 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2472 DWORD dwLightIndex,
2473 BOOL bEnable)
2475 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2476 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2478 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2480 ENTER_GL();
2481 if (bEnable) {
2482 if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
2483 /* Set the default parameters.. */
2484 TRACE(" setting default light parameters...\n");
2485 GL_IDirect3DDeviceImpl_7_SetLight(iface, dwLightIndex, &(This->light_parameters[dwLightIndex]));
2487 glEnable(GL_LIGHT0 + dwLightIndex);
2488 if ((This->active_lights & (0x00000001 << dwLightIndex)) == 0) {
2489 /* This light gets active... Need to update its parameters to GL before the next drawing */
2490 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2492 This->active_lights |= 0x00000001 << dwLightIndex;
2493 glThis->transform_state = GL_TRANSFORM_NONE;
2495 } else {
2496 glDisable(GL_LIGHT0 + dwLightIndex);
2497 This->active_lights &= ~(0x00000001 << dwLightIndex);
2499 LEAVE_GL();
2501 return DD_OK;
2504 HRESULT WINAPI
2505 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2507 ICOM_THIS(IDirect3DDeviceImpl,iface);
2508 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2510 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2512 if (dwIndex >= This->max_clipping_planes) {
2513 return DDERR_INVALIDPARAMS;
2516 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2518 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2520 /* This is to force the reset of the transformation matrices on the next drawing.
2521 * This is needed to use the correct matrices for the various clipping planes.
2523 glThis->transform_state = GL_TRANSFORM_NONE;
2525 return D3D_OK;
2528 HRESULT WINAPI
2529 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2530 LPD3DVIEWPORT7 lpData)
2532 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2533 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2535 if (TRACE_ON(ddraw)) {
2536 TRACE(" viewport is : \n");
2537 TRACE(" - dwX = %ld dwY = %ld\n",
2538 lpData->dwX, lpData->dwY);
2539 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2540 lpData->dwWidth, lpData->dwHeight);
2541 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2542 lpData->dvMinZ, lpData->dvMaxZ);
2544 ENTER_GL();
2546 /* Set the viewport */
2547 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2548 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2549 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2551 if ((lpData->dwX != This->active_viewport.dwX) ||
2552 (lpData->dwY != This->active_viewport.dwY) ||
2553 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2554 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2555 glViewport(lpData->dwX,
2556 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2557 lpData->dwWidth, lpData->dwHeight);
2560 LEAVE_GL();
2562 This->active_viewport = *lpData;
2564 return DD_OK;
2567 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2568 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2569 #else
2570 # define XCAST(fun) (void*)
2571 #endif
2573 IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2575 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2576 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2577 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2578 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2579 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2580 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2581 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2582 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2583 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2584 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2585 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2586 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2587 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2588 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2589 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2590 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2591 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2592 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2593 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2594 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2595 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2596 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2597 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2598 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2599 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2600 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2601 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2602 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2603 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2604 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2605 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2606 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2607 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2608 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2609 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2610 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2611 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2612 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2613 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2614 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2615 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2616 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2617 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2618 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2619 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2620 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2621 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2622 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2623 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2626 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2627 #undef XCAST
2628 #endif
2631 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2632 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2633 #else
2634 # define XCAST(fun) (void*)
2635 #endif
2637 IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2639 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2640 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2641 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2642 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2643 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2644 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2645 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2646 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2647 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2648 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2649 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2650 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2651 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2652 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2653 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2654 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2655 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2656 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2657 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2658 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2659 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2660 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2661 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2662 XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2663 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2664 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2665 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2666 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2667 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2668 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2669 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2670 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2671 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2672 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2673 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2674 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2675 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2676 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2677 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2678 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2679 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2680 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2683 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2684 #undef XCAST
2685 #endif
2688 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2689 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2690 #else
2691 # define XCAST(fun) (void*)
2692 #endif
2694 IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2696 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2697 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2698 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2699 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2700 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2701 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2702 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2703 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2704 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2705 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2706 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2707 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2708 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2709 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2710 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2711 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2712 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2713 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2714 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2715 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2716 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2717 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2718 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2719 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2720 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2721 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2722 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2723 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2724 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2725 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2726 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2727 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2728 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2731 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2732 #undef XCAST
2733 #endif
2736 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2737 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2738 #else
2739 # define XCAST(fun) (void*)
2740 #endif
2742 IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2744 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2745 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2746 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2747 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2748 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2749 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2750 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2751 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2752 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2753 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2754 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2755 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2756 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2757 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2758 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2759 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2760 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2761 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2762 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2763 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2764 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2765 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2768 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2769 #undef XCAST
2770 #endif
2772 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2773 WINE_GL_BUFFER_TYPE buffer_type,
2774 DWORD dwCount,
2775 LPD3DRECT lpRects,
2776 DWORD dwFlags,
2777 DWORD dwColor,
2778 D3DVALUE dvZ,
2779 DWORD dwStencil)
2781 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2782 GLbitfield bitfield = 0;
2783 D3DRECT rect;
2784 int i;
2786 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2787 if (TRACE_ON(ddraw)) {
2788 if (dwCount > 0) {
2789 int i;
2790 TRACE(" rectangles : \n");
2791 for (i = 0; i < dwCount; i++) {
2792 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2797 if (dwCount == 0) {
2798 dwCount = 1;
2799 rect.u1.x1 = 0;
2800 rect.u2.y1 = 0;
2801 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2802 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2803 lpRects = &rect;
2806 /* Clears the screen */
2807 ENTER_GL();
2809 if (dwFlags & D3DCLEAR_TARGET) {
2810 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2811 /* TODO: optimize here the case where Clear changes all the screen... */
2812 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2814 glThis->state[buffer_type] = SURFACE_GL;
2817 if (dwFlags & D3DCLEAR_ZBUFFER) {
2818 bitfield |= GL_DEPTH_BUFFER_BIT;
2819 if (glThis->depth_mask == FALSE) {
2820 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2822 if (dvZ != glThis->prev_clear_Z) {
2823 glClearDepth(dvZ);
2824 glThis->prev_clear_Z = dvZ;
2826 TRACE(" depth value : %f\n", dvZ);
2828 if (dwFlags & D3DCLEAR_STENCIL) {
2829 bitfield |= GL_STENCIL_BUFFER_BIT;
2830 if (dwStencil != glThis->prev_clear_stencil) {
2831 glClearStencil(dwStencil);
2832 glThis->prev_clear_stencil = dwStencil;
2834 TRACE(" stencil value : %ld\n", dwStencil);
2836 if (dwFlags & D3DCLEAR_TARGET) {
2837 bitfield |= GL_COLOR_BUFFER_BIT;
2838 if (dwColor != glThis->prev_clear_color) {
2839 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2840 ((dwColor >> 8) & 0xFF) / 255.0,
2841 ((dwColor >> 0) & 0xFF) / 255.0,
2842 ((dwColor >> 24) & 0xFF) / 255.0);
2843 glThis->prev_clear_color = dwColor;
2845 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2848 glEnable(GL_SCISSOR_TEST);
2849 for (i = 0; i < dwCount; i++) {
2850 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2851 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2852 glClear(bitfield);
2854 glDisable(GL_SCISSOR_TEST);
2856 if (dwFlags & D3DCLEAR_ZBUFFER) {
2857 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2860 LEAVE_GL();
2862 return DD_OK;
2865 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2866 DWORD dwCount,
2867 LPD3DRECT lpRects,
2868 DWORD dwFlags,
2869 DWORD dwColor,
2870 D3DVALUE dvZ,
2871 DWORD dwStencil)
2873 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2876 static HRESULT
2877 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2878 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2880 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2881 WINE_GL_BUFFER_TYPE buffer_type;
2883 /* First check if we BLT to the backbuffer... */
2884 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2885 buffer_type = WINE_GL_BUFFER_BACK;
2886 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2887 buffer_type = WINE_GL_BUFFER_FRONT;
2888 } else {
2889 ERR("Only BLT override to front or back-buffer is supported for now !\n");
2890 return DDERR_INVALIDPARAMS;
2893 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
2894 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
2895 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
2896 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
2897 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
2898 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
2899 * GL to do it.
2901 return DDERR_INVALIDPARAMS;
2903 *buffer_type_p = buffer_type;
2905 return DD_OK;
2908 HRESULT
2909 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
2910 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
2911 DWORD dwFlags, LPDDBLTFX lpbltfx)
2913 WINE_GL_BUFFER_TYPE buffer_type;
2914 D3DRECT rect;
2916 if (rdst) {
2917 rect.u1.x1 = rdst->left;
2918 rect.u2.y1 = rdst->top;
2919 rect.u3.x2 = rdst->right;
2920 rect.u4.y2 = rdst->bottom;
2921 } else {
2922 rect.u1.x1 = 0;
2923 rect.u2.y1 = 0;
2924 rect.u3.x2 = This->surface_desc.dwWidth;
2925 rect.u4.y2 = This->surface_desc.dwHeight;
2928 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
2930 if (dwFlags & DDBLT_COLORFILL) {
2931 /* This is easy to handle for the D3D Device... */
2932 DWORD color;
2933 GLenum prev_draw;
2935 /* The color as given in the Blt function is in the format of the frame-buffer...
2936 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2938 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
2939 if (This->palette) {
2940 color = ((0xFF000000) |
2941 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
2942 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
2943 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
2944 } else {
2945 color = 0xFF000000;
2947 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
2948 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
2949 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
2950 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
2951 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
2952 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
2953 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
2954 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
2955 color = 0xFFFFFFFF;
2956 } else {
2957 color = ((0xFF000000) |
2958 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
2959 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
2960 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
2962 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
2963 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
2964 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
2965 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
2966 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
2967 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
2968 } else {
2969 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
2970 return DDERR_INVALIDPARAMS;
2972 } else {
2973 ERR("Wrong surface type for BLT override !\n");
2974 return DDERR_INVALIDPARAMS;
2977 TRACE(" executing D3D Device override.\n");
2979 ENTER_GL();
2981 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2982 if (buffer_type == WINE_GL_BUFFER_FRONT)
2983 glDrawBuffer(GL_FRONT);
2984 else
2985 glDrawBuffer(GL_BACK);
2987 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
2989 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
2990 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
2991 glDrawBuffer(prev_draw);
2993 LEAVE_GL();
2995 return DD_OK;
2996 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
2997 /* Normal blit without any special case... */
2998 if (src != NULL) {
2999 /* And which has a SRC surface */
3000 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3002 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3003 (src_impl->d3ddevice == This->d3ddevice) &&
3004 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3005 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3006 D3DRECT src_rect;
3007 int width, height;
3008 GLenum prev_draw;
3009 WINE_GL_BUFFER_TYPE src_buffer_type;
3010 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3011 BOOLEAN initial;
3012 DWORD opt_bitmap;
3013 int x, y;
3015 if (rsrc) {
3016 src_rect.u1.x1 = rsrc->left;
3017 src_rect.u2.y1 = rsrc->top;
3018 src_rect.u3.x2 = rsrc->right;
3019 src_rect.u4.y2 = rsrc->bottom;
3020 } else {
3021 src_rect.u1.x1 = 0;
3022 src_rect.u2.y1 = 0;
3023 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3024 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3027 width = src_rect.u3.x2 - src_rect.u1.x1;
3028 height = src_rect.u4.y2 - src_rect.u2.y1;
3030 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3031 (height != (rect.u4.y2 - rect.u2.y1))) {
3032 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3033 return DDERR_INVALIDPARAMS;
3036 /* First check if we BLT from the backbuffer... */
3037 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3038 src_buffer_type = WINE_GL_BUFFER_BACK;
3039 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3040 src_buffer_type = WINE_GL_BUFFER_FRONT;
3041 } else {
3042 ERR("Unexpected case in direct buffer to buffer copy !\n");
3043 return DDERR_INVALIDPARAMS;
3046 TRACE(" using direct buffer to buffer copy.\n");
3048 ENTER_GL();
3050 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3052 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3053 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3054 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3055 LEAVE_GL();
3056 return DDERR_INVALIDPARAMS;
3059 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3060 if (buffer_type == WINE_GL_BUFFER_FRONT)
3061 glDrawBuffer(GL_FRONT);
3062 else
3063 glDrawBuffer(GL_BACK);
3065 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3066 glReadBuffer(GL_FRONT);
3067 else
3068 glReadBuffer(GL_BACK);
3070 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3071 And directly re-draws this on the destination buffer. */
3072 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3073 int get_height;
3075 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3076 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3077 else
3078 get_height = UNLOCK_TEX_SIZE;
3080 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3081 int get_width;
3083 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3084 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3085 else
3086 get_width = UNLOCK_TEX_SIZE;
3088 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3089 0, UNLOCK_TEX_SIZE - get_height,
3090 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3091 get_width, get_height);
3093 glBegin(GL_QUADS);
3094 glTexCoord2f(0.0, 0.0);
3095 glVertex3d(rect.u1.x1 + x,
3096 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3097 0.5);
3098 glTexCoord2f(1.0, 0.0);
3099 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3100 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3101 0.5);
3102 glTexCoord2f(1.0, 1.0);
3103 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3104 rect.u2.y1 + y,
3105 0.5);
3106 glTexCoord2f(0.0, 1.0);
3107 glVertex3d(rect.u1.x1 + x,
3108 rect.u2.y1 + y,
3109 0.5);
3110 glEnd();
3114 upload_surface_to_tex_memory_release();
3115 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3117 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3118 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3119 glDrawBuffer(prev_draw);
3121 LEAVE_GL();
3123 return DD_OK;
3124 } else {
3125 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3126 (this prevents calling glReadPixels) */
3127 D3DRECT src_rect;
3128 int width, height;
3129 GLenum prev_draw;
3130 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3131 BOOLEAN initial;
3132 DWORD opt_bitmap;
3133 int x, y;
3134 double x_stretch, y_stretch;
3136 if (rsrc) {
3137 src_rect.u1.x1 = rsrc->left;
3138 src_rect.u2.y1 = rsrc->top;
3139 src_rect.u3.x2 = rsrc->right;
3140 src_rect.u4.y2 = rsrc->bottom;
3141 } else {
3142 src_rect.u1.x1 = 0;
3143 src_rect.u2.y1 = 0;
3144 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3145 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3148 width = src_rect.u3.x2 - src_rect.u1.x1;
3149 height = src_rect.u4.y2 - src_rect.u2.y1;
3151 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3152 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3154 TRACE(" using memory to buffer Blt overide.\n");
3156 ENTER_GL();
3158 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3160 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3161 initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3162 ERR(" unsupported pixel format at memory to buffer Blt overide.\n");
3163 LEAVE_GL();
3164 return DDERR_INVALIDPARAMS;
3167 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3168 if (buffer_type == WINE_GL_BUFFER_FRONT)
3169 glDrawBuffer(GL_FRONT);
3170 else
3171 glDrawBuffer(GL_BACK);
3173 /* Now the serious stuff happens. This is basically the same code that for the memory
3174 flush to frame buffer ... with stretching and different rectangles added :-) */
3175 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3176 RECT flush_rect;
3178 flush_rect.top = src_rect.u2.y1 + y;
3179 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3180 src_rect.u4.y2 :
3181 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3183 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3184 flush_rect.left = src_rect.u1.x1 + x;
3185 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3186 src_rect.u3.x2 :
3187 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3189 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3191 glBegin(GL_QUADS);
3192 glTexCoord2f(0.0, 0.0);
3193 glVertex3d(rect.u1.x1 + (x * x_stretch),
3194 rect.u2.y1 + (y * y_stretch),
3195 0.5);
3196 glTexCoord2f(1.0, 0.0);
3197 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3198 rect.u2.y1 + (y * y_stretch),
3199 0.5);
3200 glTexCoord2f(1.0, 1.0);
3201 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3202 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3203 0.5);
3204 glTexCoord2f(0.0, 1.0);
3205 glVertex3d(rect.u1.x1 + (x * x_stretch),
3206 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3207 0.5);
3208 glEnd();
3212 upload_surface_to_tex_memory_release();
3213 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3215 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3216 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3217 glDrawBuffer(prev_draw);
3219 LEAVE_GL();
3221 return DD_OK;
3225 return DDERR_INVALIDPARAMS;
3228 HRESULT
3229 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3230 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3231 LPRECT rsrc, DWORD trans)
3233 RECT rsrc2;
3234 RECT rdst;
3235 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3236 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3237 WINE_GL_BUFFER_TYPE buffer_type;
3238 GLenum prev_draw;
3239 DWORD opt_bitmap;
3240 BOOLEAN initial;
3241 int width, height, x, y;
3243 /* Cannot support DSTCOLORKEY blitting... */
3244 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3246 if (rsrc == NULL) {
3247 WARN("rsrc is NULL - getting the whole surface !!\n");
3248 rsrc = &rsrc2;
3249 rsrc->left = rsrc->top = 0;
3250 rsrc->right = src_impl->surface_desc.dwWidth;
3251 rsrc->bottom = src_impl->surface_desc.dwHeight;
3252 } else {
3253 rsrc2 = *rsrc;
3254 rsrc = &rsrc2;
3257 rdst.left = dstx;
3258 rdst.top = dsty;
3259 rdst.right = dstx + (rsrc->right - rsrc->left);
3260 if (rdst.right > This->surface_desc.dwWidth) {
3261 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3262 rdst.right = This->surface_desc.dwWidth;
3264 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3265 if (rdst.bottom > This->surface_desc.dwHeight) {
3266 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3267 rdst.bottom = This->surface_desc.dwHeight;
3270 width = rsrc->right - rsrc->left;
3271 height = rsrc->bottom - rsrc->top;
3273 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3275 TRACE(" using BltFast memory to frame buffer overide.\n");
3277 ENTER_GL();
3279 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3281 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3282 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3283 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3284 ERR(" unsupported pixel format at memory to buffer Blt overide.\n");
3285 LEAVE_GL();
3286 return DDERR_INVALIDPARAMS;
3289 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3290 if (buffer_type == WINE_GL_BUFFER_FRONT)
3291 glDrawBuffer(GL_FRONT);
3292 else
3293 glDrawBuffer(GL_BACK);
3295 /* Now the serious stuff happens. This is basically the same code that for the memory
3296 flush to frame buffer but with different rectangles for source and destination :-) */
3297 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3298 RECT flush_rect;
3300 flush_rect.top = rsrc->top + y;
3301 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3302 rsrc->bottom :
3303 (rsrc->top + y + UNLOCK_TEX_SIZE));
3305 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3306 flush_rect.left = rsrc->left + x;
3307 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3308 rsrc->right :
3309 (rsrc->left + x + UNLOCK_TEX_SIZE));
3311 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3313 glBegin(GL_QUADS);
3314 glTexCoord2f(0.0, 0.0);
3315 glVertex3d(rdst.left + x,
3316 rdst.top + y,
3317 0.5);
3318 glTexCoord2f(1.0, 0.0);
3319 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3320 rdst.top + y,
3321 0.5);
3322 glTexCoord2f(1.0, 1.0);
3323 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3324 rdst.top + (y + UNLOCK_TEX_SIZE),
3325 0.5);
3326 glTexCoord2f(0.0, 1.0);
3327 glVertex3d(rdst.left + x,
3328 rdst.top + (y + UNLOCK_TEX_SIZE),
3329 0.5);
3330 glEnd();
3334 upload_surface_to_tex_memory_release();
3335 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3337 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3338 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3339 glDrawBuffer(prev_draw);
3341 LEAVE_GL();
3343 return DD_OK;
3346 void
3347 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3349 GLfloat height, width;
3350 GLfloat trans_mat[16];
3352 TRACE("(%p)\n", This);
3354 width = This->surface->surface_desc.dwWidth;
3355 height = This->surface->surface_desc.dwHeight;
3357 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3358 * to OpenGL screen coordinates (ie the upper left corner is not the same).
3360 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3361 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3362 #if 0
3363 /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3364 * that the Z coordinate needs to be given to GL unchanged.
3366 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 2.0; trans_mat[14] = -1.0;
3367 #endif
3368 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = 0.0;
3369 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3371 ENTER_GL();
3372 glMatrixMode(GL_MODELVIEW);
3373 glLoadIdentity();
3374 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3375 Correctness Tips section).
3377 Basically, from what I understood, if the game does not filter the font texture,
3378 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3379 one and we will have strange artifacts (as the rounding and stuff may give different results
3380 for different pixels, ie sometimes take the left pixel, sometimes the right).
3382 glTranslatef(0.375, 0.375, 0);
3383 glMatrixMode(GL_PROJECTION);
3384 glLoadMatrixf(trans_mat);
3385 LEAVE_GL();
3388 void
3389 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3390 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3392 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3394 ENTER_GL();
3395 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3396 glMatrixMode(GL_MODELVIEW);
3397 glLoadMatrixf((float *) view_mat);
3399 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3400 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3401 GLint i;
3402 DWORD runner;
3403 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3404 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3405 GLdouble plane[4];
3407 plane[0] = This->clipping_planes[i].plane[0];
3408 plane[1] = This->clipping_planes[i].plane[1];
3409 plane[2] = This->clipping_planes[i].plane[2];
3410 plane[3] = This->clipping_planes[i].plane[3];
3412 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3416 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3417 GLint i;
3418 DWORD runner;
3420 for (i = 0, runner = 0x00000001; i < MAX_LIGHTS; i++, runner <<= 1) {
3421 if (runner & This->active_lights) {
3422 switch (This->light_parameters[i].dltType) {
3423 case D3DLIGHT_DIRECTIONAL: {
3424 float direction[4];
3425 float cut_off = 180.0;
3427 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3428 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3429 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3430 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3432 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3433 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3434 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3435 direction[3] = 0.0;
3436 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3437 } break;
3439 case D3DLIGHT_POINT: {
3440 float position[4];
3441 float cut_off = 180.0;
3443 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3444 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3445 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3446 position[0] = This->light_parameters[i].dvPosition.u1.x;
3447 position[1] = This->light_parameters[i].dvPosition.u2.y;
3448 position[2] = This->light_parameters[i].dvPosition.u3.z;
3449 position[3] = 1.0;
3450 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3451 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3452 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3453 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3454 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3455 } break;
3457 case D3DLIGHT_SPOT: {
3458 float direction[4];
3459 float position[4];
3460 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3462 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3463 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3464 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3466 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3467 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3468 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3469 direction[3] = 0.0;
3470 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3471 position[0] = This->light_parameters[i].dvPosition.u1.x;
3472 position[1] = This->light_parameters[i].dvPosition.u2.y;
3473 position[2] = This->light_parameters[i].dvPosition.u3.z;
3474 position[3] = 1.0;
3475 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3476 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3477 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3478 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3479 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3480 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &(This->light_parameters[i].dvFalloff));
3481 } break;
3483 default:
3484 /* No warning here as it's already done at light setting */
3485 break;
3491 glMultMatrixf((float *) world_mat);
3493 if ((matrices & PROJMAT_CHANGED) != 0) {
3494 glMatrixMode(GL_PROJECTION);
3495 glLoadMatrixf((float *) proj_mat);
3497 LEAVE_GL();
3500 void
3501 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3503 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3504 DWORD tex_mat, tex_stage;
3506 TRACE("(%p,%08lx)\n", This, matrices);
3508 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3509 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3510 /* This will force an update of the transform state at the next drawing. */
3511 glThis->transform_state = GL_TRANSFORM_NONE;
3514 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3515 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3517 ENTER_GL();
3518 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3519 GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3520 if (matrices & tex_mat) {
3521 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3522 int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3524 if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3525 if (glThis->current_active_tex_unit != unit) {
3526 GL_extensions.glActiveTexture(unit);
3527 glThis->current_active_tex_unit = unit;
3529 glMatrixMode(GL_TEXTURE);
3530 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3532 This->tex_mat_is_identity[tex_stage] = is_identity;
3533 } else {
3534 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3535 if (glThis->current_active_tex_unit != unit) {
3536 GL_extensions.glActiveTexture(unit);
3537 glThis->current_active_tex_unit = unit;
3539 glMatrixMode(GL_TEXTURE);
3540 glLoadIdentity();
3541 This->tex_mat_is_identity[tex_stage] = TRUE;
3546 LEAVE_GL();
3550 /* TODO for both these functions :
3551 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3552 by other OpenGL code in D3D
3553 - handle the case where no 'Begin / EndScene' was done between two locks
3554 - handle the rectangles in the unlock too
3555 - handle pitch correctly...
3557 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3559 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3560 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3561 WINE_GL_BUFFER_TYPE buffer_type;
3562 RECT loc_rect;
3564 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3565 buffer_type = WINE_GL_BUFFER_FRONT;
3566 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3567 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3568 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3570 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3571 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3572 buffer_type = WINE_GL_BUFFER_BACK;
3573 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3574 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3575 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3577 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3578 } else {
3579 ERR("Wrong surface type for locking !\n");
3580 return;
3583 if (pRect == NULL) {
3584 loc_rect.top = 0;
3585 loc_rect.left = 0;
3586 loc_rect.bottom = This->surface_desc.dwHeight;
3587 loc_rect.right = This->surface_desc.dwWidth;
3588 pRect = &loc_rect;
3591 /* Try to acquire the device critical section */
3592 EnterCriticalSection(&(d3d_dev->crit));
3594 if (gl_d3d_dev->lock_rect_valid[buffer_type] == TRUE) {
3595 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3596 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3598 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3600 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3601 /* Check if the new rectangle is in the previous one or not.
3602 If it is not, flush first the previous locks on screen.
3604 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3605 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3606 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3607 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3608 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3609 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3610 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3611 pRect->left, pRect->top, pRect->right, pRect->bottom,
3612 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3613 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3614 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3616 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3617 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3619 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3620 } else {
3621 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3624 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3625 /* If the surface is already in memory, no need to do anything here... */
3626 GLenum buffer_format;
3627 GLenum buffer_color;
3628 int y;
3629 char *dst;
3631 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3632 pRect->left, pRect->top, pRect->right, pRect->bottom);
3634 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3635 may only write to the device... But when we will blit it back to the screen, we need
3636 also to blit correctly the parts the application did not overwrite... */
3638 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3639 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3640 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3641 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3642 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3643 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3644 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3645 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3646 buffer_color = GL_RGB;
3647 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3648 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3649 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3650 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3651 buffer_format = GL_UNSIGNED_BYTE;
3652 buffer_color = GL_RGB;
3653 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3654 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3655 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3656 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3657 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3658 buffer_color = GL_BGRA;
3659 } else {
3660 ERR(" unsupported pixel format at device locking.\n");
3661 return;
3663 } else {
3664 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3665 return;
3668 ENTER_GL();
3670 if (buffer_type == WINE_GL_BUFFER_FRONT)
3671 /* Application wants to lock the front buffer */
3672 glReadBuffer(GL_FRONT);
3673 else
3674 /* Application wants to lock the back buffer */
3675 glReadBuffer(GL_BACK);
3677 dst = ((char *)This->surface_desc.lpSurface) +
3678 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3680 if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3681 /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3682 * could not be bothered considering the rare cases where it may be useful :-)
3684 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3685 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3686 y--) {
3687 glReadPixels(pRect->left, y,
3688 pRect->right - pRect->left, 1,
3689 buffer_color, buffer_format, dst);
3690 dst += This->surface_desc.u1.lPitch;
3692 } else {
3693 /* Faster path for surface copy. Note that I can use static variables here as I am
3694 * protected by the OpenGL critical section so this function won't be called by
3695 * two threads at the same time.
3697 static char *buffer = NULL;
3698 static int buffer_width = 0;
3699 char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3700 int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3702 glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3703 pRect->right - pRect->left, pRect->bottom - pRect->top,
3704 buffer_color, buffer_format, dst);
3706 if (current_width > buffer_width) {
3707 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3708 buffer_width = current_width;
3709 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3711 for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3712 memcpy(buffer, dst, current_width);
3713 memcpy(dst, dst2, current_width);
3714 memcpy(dst2, buffer, current_width);
3715 dst += This->surface_desc.u1.lPitch;
3716 dst2 -= This->surface_desc.u1.lPitch;
3720 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3722 #if 0
3723 /* I keep this code here as it's very useful to debug :-) */
3725 static int flush_count = 0;
3726 char buf[128];
3727 FILE *f;
3729 if ((++flush_count % 50) == 0) {
3730 sprintf(buf, "lock_%06d.pnm", flush_count);
3731 f = fopen(buf, "wb");
3732 DDRAW_dump_surface_to_disk(This, f);
3735 #endif
3737 LEAVE_GL();
3741 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3742 RECT loc_rect;
3743 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3744 int x, y;
3745 BOOLEAN initial;
3746 DWORD opt_bitmap;
3748 /* Note : no need here to lock the 'device critical section' as we are already protected by
3749 the GL critical section. */
3751 if (pRect == NULL) {
3752 loc_rect.top = 0;
3753 loc_rect.left = 0;
3754 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3755 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3756 pRect = &loc_rect;
3759 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3761 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3763 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3764 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3765 ERR(" unsupported pixel format at frame buffer flush.\n");
3766 return;
3769 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3770 RECT flush_rect;
3772 flush_rect.top = y;
3773 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3775 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3776 /* First, upload the texture... */
3777 flush_rect.left = x;
3778 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3780 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3782 glBegin(GL_QUADS);
3783 glTexCoord2f(0.0, 0.0);
3784 glVertex3d(x, y, 0.5);
3785 glTexCoord2f(1.0, 0.0);
3786 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3787 glTexCoord2f(1.0, 1.0);
3788 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3789 glTexCoord2f(0.0, 1.0);
3790 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3791 glEnd();
3795 upload_surface_to_tex_memory_release();
3796 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3798 #if 0
3799 /* I keep this code here as it's very useful to debug :-) */
3801 static int flush_count = 0;
3802 char buf[128];
3803 FILE *f;
3805 if ((++flush_count % 50) == 0) {
3806 sprintf(buf, "flush_%06d.pnm", flush_count);
3807 f = fopen(buf, "wb");
3808 DDRAW_dump_surface_to_disk(surf, f);
3811 #endif
3814 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3816 WINE_GL_BUFFER_TYPE buffer_type;
3817 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3818 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3820 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3821 buffer_type = WINE_GL_BUFFER_FRONT;
3822 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3823 buffer_type = WINE_GL_BUFFER_BACK;
3824 } else {
3825 ERR("Wrong surface type for locking !\n");
3826 return;
3829 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3830 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3831 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3833 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3835 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3836 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3837 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3838 GLenum prev_draw;
3840 TRACE(" flushing front buffer immediatly on screen.\n");
3842 ENTER_GL();
3843 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3844 glDrawBuffer(GL_FRONT);
3845 /* Note: we do not use the application provided lock rectangle but our own stored at
3846 lock time. This is because in old D3D versions, the 'lock' parameter did not
3847 exist.
3849 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]);
3850 glDrawBuffer(prev_draw);
3851 LEAVE_GL();
3852 } else {
3853 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3857 /* And 'frees' the device critical section */
3858 LeaveCriticalSection(&(d3d_dev->crit));
3861 static void
3862 apply_texture_state(IDirect3DDeviceImpl *This)
3864 int stage, state;
3866 /* Initialize texture stages states */
3867 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3868 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3869 if (This->state_block.set_flags.texture_stage_state[stage][state] == TRUE) {
3870 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3871 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3877 HRESULT
3878 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, BOOLEAN from_surface)
3880 IDirect3DDeviceImpl *object;
3881 IDirect3DDeviceGLImpl *gl_object;
3882 IDirectDrawSurfaceImpl *surf;
3883 HDC device_context;
3884 XVisualInfo *vis;
3885 int num;
3886 int tex_num;
3887 XVisualInfo template;
3888 GLenum buffer = GL_FRONT;
3889 int light;
3891 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
3892 if (object == NULL) return DDERR_OUTOFMEMORY;
3894 gl_object = (IDirect3DDeviceGLImpl *) object;
3896 object->ref = 1;
3897 object->d3d = d3d;
3898 object->surface = surface;
3899 object->set_context = set_context;
3900 object->clear = d3ddevice_clear_back;
3901 object->set_matrices = d3ddevice_set_matrices;
3902 object->matrices_updated = d3ddevice_matrices_updated;
3903 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
3905 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
3907 InitializeCriticalSection(&(object->crit));
3909 TRACE(" device critical section : %p\n", &(object->crit));
3911 /* This is just a hack for some badly done games :-/ */
3912 if (from_surface) {
3913 gl_object->version = 1;
3914 TRACE(" using D3D1 special hacks.\n");
3915 } else
3916 gl_object->version = 7;
3918 device_context = GetDC(surface->ddraw_owner->window);
3919 gl_object->display = get_display(device_context);
3920 gl_object->drawable = get_drawable(device_context);
3921 ReleaseDC(surface->ddraw_owner->window,device_context);
3923 ENTER_GL();
3924 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
3925 vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
3926 if (vis == NULL) {
3927 HeapFree(GetProcessHeap(), 0, object);
3928 ERR("No visual found !\n");
3929 LEAVE_GL();
3930 return DDERR_INVALIDPARAMS;
3931 } else {
3932 TRACE(" visual found\n");
3935 gl_object->gl_context = glXCreateContext(gl_object->display, vis,
3936 NULL, GL_TRUE);
3938 if (gl_object->gl_context == NULL) {
3939 HeapFree(GetProcessHeap(), 0, object);
3940 ERR("Error in context creation !\n");
3941 LEAVE_GL();
3942 return DDERR_INVALIDPARAMS;
3943 } else {
3944 TRACE(" context created (%p)\n", gl_object->gl_context);
3947 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
3948 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3949 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
3950 surf->aux_ctx = (LPVOID) object;
3951 surf->aux_data = (LPVOID) gl_object->drawable;
3952 surf->aux_flip = opengl_flip;
3953 buffer = GL_BACK;
3954 break;
3957 /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
3958 if (surf == NULL) {
3959 TRACE(" no double buffering : drawing on the front buffer\n");
3960 buffer = GL_FRONT;
3963 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3964 IDirectDrawSurfaceImpl *surf2;
3965 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
3966 for (; surf2 != NULL; surf2 = surf2->next_attached) {
3967 TRACE(" checking surface %p :", surf2);
3968 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
3969 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
3970 /* Override the Lock / Unlock function for all these surfaces */
3971 surf2->lock_update_prev = surf2->lock_update;
3972 surf2->lock_update = d3ddevice_lock_update;
3973 surf2->unlock_update_prev = surf2->unlock_update;
3974 surf2->unlock_update = d3ddevice_unlock_update;
3975 /* And install also the blt / bltfast overrides */
3976 surf2->aux_blt = d3ddevice_blt;
3977 surf2->aux_bltfast = d3ddevice_bltfast;
3979 TRACE(" overiding direct surface access.\n");
3980 } else {
3981 TRACE(" no overide.\n");
3983 surf2->d3ddevice = object;
3987 /* Set the various light parameters */
3988 for (light = 0; light < MAX_LIGHTS; light++) {
3989 /* Only set the fields that are not zero-created */
3990 object->light_parameters[light].dltType = D3DLIGHT_DIRECTIONAL;
3991 object->light_parameters[light].dcvDiffuse.u1.r = 1.0;
3992 object->light_parameters[light].dcvDiffuse.u2.g = 1.0;
3993 object->light_parameters[light].dcvDiffuse.u3.b = 1.0;
3994 object->light_parameters[light].dvDirection.u3.z = 1.0;
3997 /* Allocate memory for the matrices */
3998 object->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3999 object->view_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4000 object->proj_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4001 memcpy(object->world_mat, id_mat, 16 * sizeof(float));
4002 memcpy(object->view_mat , id_mat, 16 * sizeof(float));
4003 memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
4004 for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
4005 object->tex_mat[tex_num] = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4006 memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
4007 object->tex_mat_is_identity[tex_num] = TRUE;
4010 /* Initialisation */
4011 TRACE(" setting current context\n");
4012 object->set_context(object);
4013 TRACE(" current context set\n");
4015 /* allocate the clipping planes */
4016 object->max_clipping_planes = opengl_device_caps.wMaxUserClipPlanes;
4017 object->clipping_planes = (d3d7clippingplane*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
4019 glHint(GL_FOG_HINT,GL_NICEST);
4021 /* Initialize the various GL contexts to be in sync with what we store locally */
4022 glClearDepth(0.0);
4023 glClearStencil(0);
4024 glClearColor(0.0, 0.0, 0.0, 0.0);
4025 glDepthMask(GL_TRUE);
4026 gl_object->depth_mask = TRUE;
4027 glEnable(GL_DEPTH_TEST);
4028 gl_object->depth_test = TRUE;
4029 glDisable(GL_ALPHA_TEST);
4030 glDisable(GL_STENCIL_TEST);
4031 glDisable(GL_CULL_FACE);
4032 glDisable(GL_LIGHTING);
4033 glDisable(GL_BLEND);
4034 glDisable(GL_FOG);
4035 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4036 gl_object->current_tex_env = GL_REPLACE;
4037 gl_object->current_active_tex_unit = GL_TEXTURE0_WINE;
4038 if (GL_extensions.glActiveTexture != NULL) {
4039 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
4041 gl_object->current_alpha_test_ref = 0.0;
4042 gl_object->current_alpha_test_func = GL_ALWAYS;
4043 glAlphaFunc(GL_ALWAYS, 0.0);
4045 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4046 glDrawBuffer(buffer);
4047 glReadBuffer(buffer);
4048 /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
4049 LEAVE_GL();
4051 gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
4052 gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
4054 /* fill_device_capabilities(d3d->ddraw); */
4056 ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
4057 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
4058 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
4059 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
4061 *obj = object;
4063 TRACE(" creating implementation at %p.\n", *obj);
4065 /* And finally warn D3D that this device is now present */
4066 object->d3d->d3d_added_device(object->d3d, object);
4068 /* FIXME: Should handle other versions than just 7 */
4069 InitDefaultStateBlock(&object->state_block, 7);
4070 /* Apply default render state and texture stage state values */
4071 apply_render_state(object, &object->state_block);
4072 apply_texture_state(object);
4074 /* And fill the fog table with the default fog value */
4075 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4077 return DD_OK;
4080 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4082 pc->dwSize = sizeof(*pc);
4083 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4084 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4085 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4086 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4087 D3DPRASTERCAPS_ZFOG;
4088 if (GL_extensions.mipmap_lodbias == TRUE) {
4089 pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4091 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4092 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4093 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4094 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4095 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4096 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4097 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4098 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4099 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4100 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4101 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4102 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4103 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4104 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4105 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4106 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4107 D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4108 D3DPTFILTERCAPS_MIPFPOINT;
4109 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4110 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4111 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4112 if (GL_extensions.mirrored_repeat == TRUE) {
4113 pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4115 pc->dwStippleWidth = 32;
4116 pc->dwStippleHeight = 32;
4119 static void fill_caps(void)
4121 GLint max_clip_planes;
4122 GLint depth_bits;
4124 /* Fill first all the fields with default values which will be overriden later on with
4125 correct ones from the GL code
4127 opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4128 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4129 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4130 /* D3D 7 capabilities */
4131 D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4132 fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4133 fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4134 opengl_device_caps.dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
4135 opengl_device_caps.dwMinTextureWidth = 1;
4136 opengl_device_caps.dwMinTextureHeight = 1;
4137 opengl_device_caps.dwMaxTextureWidth = 1024;
4138 opengl_device_caps.dwMaxTextureHeight = 1024;
4139 opengl_device_caps.dwMaxTextureRepeat = 16;
4140 opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4141 opengl_device_caps.dwMaxAnisotropy = 0;
4142 opengl_device_caps.dvGuardBandLeft = 0.0;
4143 opengl_device_caps.dvGuardBandRight = 0.0;
4144 opengl_device_caps.dvGuardBandTop = 0.0;
4145 opengl_device_caps.dvGuardBandBottom = 0.0;
4146 opengl_device_caps.dvExtentsAdjust = 0.0;
4147 opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4148 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4149 opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4150 D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4151 D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4152 if (GL_extensions.max_texture_units != 0) {
4153 opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4154 opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4155 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4156 } else {
4157 opengl_device_caps.wMaxTextureBlendStages = 1;
4158 opengl_device_caps.wMaxSimultaneousTextures = 1;
4159 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4161 opengl_device_caps.dwMaxActiveLights = 16;
4162 opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4163 opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4164 opengl_device_caps.wMaxUserClipPlanes = 1;
4165 opengl_device_caps.wMaxVertexBlendMatrices = 0;
4166 opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4167 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4168 opengl_device_caps.dwReserved1 = 0;
4169 opengl_device_caps.dwReserved2 = 0;
4170 opengl_device_caps.dwReserved3 = 0;
4171 opengl_device_caps.dwReserved4 = 0;
4173 /* And now some GL overides :-) */
4174 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4175 opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4176 opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4177 TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4179 glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4180 TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4182 glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4183 opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4184 TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4186 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4187 TRACE(": Z bits = %d\n", depth_bits);
4188 switch (depth_bits) {
4189 case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4190 case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4191 case 32:
4192 default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4196 BOOL
4197 d3ddevice_init_at_startup(void *gl_handle)
4199 XVisualInfo template;
4200 XVisualInfo *vis;
4201 HDC device_context;
4202 Display *display;
4203 Visual *visual;
4204 Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4205 XWindowAttributes win_attr;
4206 GLXContext gl_context;
4207 int num;
4208 const char *glExtensions;
4209 const char *glVersion;
4210 const char *glXExtensions = NULL;
4211 const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4212 int major, minor, patch, num_parsed;
4214 TRACE("Initializing GL...\n");
4216 /* Get a default rendering context to have the 'caps' function query some info from GL */
4217 device_context = GetDC(0);
4218 display = get_display(device_context);
4219 ReleaseDC(0, device_context);
4221 ENTER_GL();
4222 if (XGetWindowAttributes(display, drawable, &win_attr)) {
4223 visual = win_attr.visual;
4224 } else {
4225 visual = DefaultVisual(display, DefaultScreen(display));
4227 template.visualid = XVisualIDFromVisual(visual);
4228 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4229 if (vis == NULL) {
4230 LEAVE_GL();
4231 WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4232 return FALSE;
4234 gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4236 if (gl_context == NULL) {
4237 LEAVE_GL();
4238 WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4239 return FALSE;
4241 if (glXMakeCurrent(display, drawable, gl_context) == False) {
4242 glXDestroyContext(display, gl_context);
4243 LEAVE_GL();
4244 WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4245 return FALSE;
4248 /* Then, query all extensions */
4249 glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4250 glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4251 glVersion = (const char *) glGetString(GL_VERSION);
4252 if (gl_handle != NULL) {
4253 pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4256 /* Parse the GL version string */
4257 num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4258 if (num_parsed == 1) {
4259 minor = 0;
4260 patch = 0;
4261 } else if (num_parsed == 2) {
4262 patch = 0;
4264 TRACE("GL version %d.%d.%d\n", major, minor, patch);
4266 /* And starts to fill the extension context properly */
4267 memset(&GL_extensions, 0, sizeof(GL_extensions));
4268 TRACE("GL supports following extensions used by Wine :\n");
4270 /* Mirrored Repeat extension :
4271 - GL_ARB_texture_mirrored_repeat
4272 - GL_IBM_texture_mirrored_repeat
4273 - GL >= 1.4
4275 if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4276 (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4277 (major > 1) ||
4278 ((major == 1) && (minor >= 4))) {
4279 TRACE(" - mirrored repeat\n");
4280 GL_extensions.mirrored_repeat = TRUE;
4283 /* Texture LOD Bias :
4284 - GL_EXT_texture_lod_bias
4286 if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4287 TRACE(" - texture lod bias\n");
4288 GL_extensions.mipmap_lodbias = TRUE;
4291 /* For all subsequent extensions, we need glXGetProcAddress */
4292 if (pglXGetProcAddressARB != NULL) {
4293 /* Multi-texturing :
4294 - GL_ARB_multitexture
4295 - GL >= 1.2.1
4297 if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4298 (major > 1) ||
4299 ((major == 1) && (minor > 2)) ||
4300 ((major == 1) && (minor == 2) && (patch >= 1))) {
4301 glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4302 TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4303 /* We query the ARB version to be the most portable we can... */
4304 GL_extensions.glActiveTexture = pglXGetProcAddressARB("glActiveTextureARB");
4305 GL_extensions.glMultiTexCoord2fv = pglXGetProcAddressARB("glMultiTexCoord2fv");
4306 GL_extensions.glClientActiveTexture = pglXGetProcAddressARB("glClientActiveTextureARB");
4309 if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4310 TRACE(" - S3TC compression supported\n");
4311 GL_extensions.s3tc_compressed_texture = TRUE;
4312 GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB("glCompressedTexImage2D");
4313 GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB("glCompressedTexSubImage2D");
4317 /* Fill the D3D capabilities according to what GL tells us... */
4318 fill_caps();
4320 /* And frees this now-useless context */
4321 glXMakeCurrent(display, None, NULL);
4322 glXDestroyContext(display, gl_context);
4323 LEAVE_GL();
4325 return TRUE;