Moved d3ddevice and direct3d objects files to ddraw root dir.
[wine/wine-kai.git] / dlls / ddraw / device_opengl.c
blobc514ec802af962c42c5e9b964aadbfa37e7e3857
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
33 #define CONST_VTABLE
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "objbase.h"
39 #include "wingdi.h"
40 #include "ddraw.h"
41 #include "d3d.h"
42 #include "wine/debug.h"
43 #include "wine/library.h"
45 #include "d3d_private.h"
46 #include "opengl_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
49 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
51 /* x11drv GDI escapes */
52 #define X11DRV_ESCAPE 6789
53 enum x11drv_escape_codes
55 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
56 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
57 X11DRV_GET_FONT, /* get current X font for a DC */
60 /* They are non-static as they are used by Direct3D in the creation function */
61 const GUID IID_D3DDEVICE_OpenGL = {
62 0x31416d44,
63 0x86ae,
64 0x11d2,
65 { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
68 const float id_mat[16] = {
69 1.0, 0.0, 0.0, 0.0,
70 0.0, 1.0, 0.0, 0.0,
71 0.0, 0.0, 1.0, 0.0,
72 0.0, 0.0, 0.0, 1.0
75 /* This is filled at DLL loading time */
76 static D3DDEVICEDESC7 opengl_device_caps;
77 GL_EXTENSIONS_LIST GL_extensions;
79 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
80 D3DPRIMITIVETYPE d3dptPrimitiveType,
81 DWORD d3dvtVertexType,
82 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
83 DWORD dwVertexCount,
84 LPWORD dwIndices,
85 DWORD dwIndexCount,
86 DWORD dwFlags) ;
88 static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
90 /* retrieve the X display to use on a given DC */
91 inline static Display *get_display( HDC hdc )
93 Display *display;
94 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
96 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
97 sizeof(display), (LPSTR)&display )) display = NULL;
99 return display;
102 #define UNLOCK_TEX_SIZE 256
104 #define DEPTH_RANGE_BIT (0x00000001 << 0)
105 #define VIEWPORT_BIT (0x00000001 << 1)
107 static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
108 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
109 DWORD opt_bitmap = 0x00000000;
111 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
112 ((d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE))) {
113 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
114 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
115 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
117 /* Disable multi-texturing for level 1 to disable all others */
118 glDisable(GL_TEXTURE_2D);
120 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
121 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
122 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
124 if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
125 (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
126 glEnable(GL_TEXTURE_2D);
127 if (gl_d3d_dev->unlock_tex == 0) {
128 glGenTextures(1, &gl_d3d_dev->unlock_tex);
129 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
130 *initial = TRUE;
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
135 } else {
136 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
137 *initial = FALSE;
139 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
140 glMatrixMode(GL_TEXTURE);
141 glLoadIdentity();
144 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
145 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
146 d3ddevice_set_ortho(d3d_dev);
149 if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
150 glEnable(GL_SCISSOR_TEST);
151 if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
152 (d3d_dev->active_viewport.dvMaxZ != 1.0)) {
153 glDepthRange(0.0, 1.0);
154 opt_bitmap |= DEPTH_RANGE_BIT;
156 if ((d3d_dev->active_viewport.dwX != 0) ||
157 (d3d_dev->active_viewport.dwY != 0) ||
158 (d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
159 (d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
160 glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
161 opt_bitmap |= VIEWPORT_BIT;
163 glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
164 pRect->right - pRect->left, pRect->bottom - pRect->top);
165 if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
166 if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
167 if (use_alpha) {
168 if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
169 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
170 glAlphaFunc(GL_NOTEQUAL, 0.0);
171 } else {
172 if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
174 if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
175 if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
176 if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
177 if (gl_d3d_dev->current_tex_env != GL_REPLACE)
178 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
180 return opt_bitmap;
183 static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
184 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
186 /* And restore all the various states modified by this code */
187 if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
188 if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
189 if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
190 glEnable(GL_ALPHA_TEST);
191 else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
192 glDisable(GL_ALPHA_TEST);
193 if (use_alpha) {
194 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
195 glAlphaFunc(gl_d3d_dev->current_alpha_test_func, gl_d3d_dev->current_alpha_test_ref);
197 if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
198 if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
199 if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
200 if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
201 glDisable(GL_SCISSOR_TEST);
202 if (opt_bitmap & DEPTH_RANGE_BIT) {
203 glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
205 if (opt_bitmap & VIEWPORT_BIT) {
206 glViewport(d3d_dev->active_viewport.dwX,
207 d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
208 d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
210 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
211 d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
214 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
215 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
216 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
218 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
219 /* Note that here we could directly re-bind the previous texture... But it would in some case be a spurious
220 bind if ever the game changes the texture just after.
222 So choose 0x00000001 to postpone the binding to the next time we draw something on screen. */
223 gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
224 if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
226 /* And re-enabled if needed texture level 1 */
227 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
228 (d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
229 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
230 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
231 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
233 glEnable(GL_TEXTURE_2D);
237 /* retrieve the X drawable to use on a given DC */
238 inline static Drawable get_drawable( HDC hdc )
240 Drawable drawable;
241 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
243 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
244 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
246 return drawable;
249 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
251 IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
252 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
254 TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
255 ENTER_GL();
256 if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
257 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]);
259 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
260 gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
261 glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
262 LEAVE_GL();
264 return TRUE;
268 /*******************************************************************************
269 * OpenGL static functions
271 static void set_context(IDirect3DDeviceImpl* This)
273 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
275 TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
276 ENTER_GL();
277 if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
278 ERR("Error in setting current context (context %p drawable %ld)!\n",
279 glThis->gl_context, glThis->drawable);
281 LEAVE_GL();
284 static void fill_opengl_caps(D3DDEVICEDESC *d1)
286 d1->dwSize = sizeof(*d1);
287 d1->dwFlags = D3DDD_COLORMODEL | D3DDD_DEVCAPS | D3DDD_TRANSFORMCAPS | D3DDD_BCLIPPING | D3DDD_LIGHTINGCAPS |
288 D3DDD_LINECAPS | D3DDD_TRICAPS | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH |
289 D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT;
290 d1->dcmColorModel = D3DCOLOR_RGB;
291 d1->dwDevCaps = opengl_device_caps.dwDevCaps;
292 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
293 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
294 d1->bClipping = TRUE;
295 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
296 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
297 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
298 d1->dlcLightingCaps.dwNumLights = opengl_device_caps.dwMaxActiveLights;
299 d1->dpcLineCaps = opengl_device_caps.dpcLineCaps;
300 d1->dpcTriCaps = opengl_device_caps.dpcTriCaps;
301 d1->dwDeviceRenderBitDepth = opengl_device_caps.dwDeviceRenderBitDepth;
302 d1->dwDeviceZBufferBitDepth = opengl_device_caps.dwDeviceZBufferBitDepth;
303 d1->dwMaxBufferSize = 0;
304 d1->dwMaxVertexCount = 65536;
305 d1->dwMinTextureWidth = opengl_device_caps.dwMinTextureWidth;
306 d1->dwMinTextureHeight = opengl_device_caps.dwMinTextureHeight;
307 d1->dwMaxTextureWidth = opengl_device_caps.dwMaxTextureWidth;
308 d1->dwMaxTextureHeight = opengl_device_caps.dwMaxTextureHeight;
309 d1->dwMinStippleWidth = 1;
310 d1->dwMinStippleHeight = 1;
311 d1->dwMaxStippleWidth = 32;
312 d1->dwMaxStippleHeight = 32;
313 d1->dwMaxTextureRepeat = opengl_device_caps.dwMaxTextureRepeat;
314 d1->dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureAspectRatio;
315 d1->dwMaxAnisotropy = opengl_device_caps.dwMaxAnisotropy;
316 d1->dvGuardBandLeft = opengl_device_caps.dvGuardBandLeft;
317 d1->dvGuardBandRight = opengl_device_caps.dvGuardBandRight;
318 d1->dvGuardBandTop = opengl_device_caps.dvGuardBandTop;
319 d1->dvGuardBandBottom = opengl_device_caps.dvGuardBandBottom;
320 d1->dvExtentsAdjust = opengl_device_caps.dvExtentsAdjust;
321 d1->dwStencilCaps = opengl_device_caps.dwStencilCaps;
322 d1->dwFVFCaps = opengl_device_caps.dwFVFCaps;
323 d1->dwTextureOpCaps = opengl_device_caps.dwTextureOpCaps;
324 d1->wMaxTextureBlendStages = opengl_device_caps.wMaxTextureBlendStages;
325 d1->wMaxSimultaneousTextures = opengl_device_caps.wMaxSimultaneousTextures;
328 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
330 *d = opengl_device_caps;
333 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
335 D3DDEVICEDESC dref, d1, d2;
336 HRESULT ret_value;
338 /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
339 Let's put the string in a sufficiently sized array in writable memory. */
340 char device_name[50];
341 strcpy(device_name,"direct3d");
343 fill_opengl_caps(&dref);
345 if (version > 1) {
346 /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
347 char interface_name[] = "WINE Reference Direct3DX using OpenGL";
348 TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
349 d1 = dref;
350 d2 = dref;
351 ret_value = cb((LPIID) &IID_IDirect3DRefDevice, interface_name, device_name, &d1, &d2, context);
352 if (ret_value != D3DENUMRET_OK)
353 return ret_value;
357 char interface_name[] = "WINE Direct3DX using OpenGL";
358 TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
359 d1 = dref;
360 d2 = dref;
361 ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, interface_name, device_name, &d1, &d2, context);
362 if (ret_value != D3DENUMRET_OK)
363 return ret_value;
366 return D3DENUMRET_OK;
369 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
371 D3DDEVICEDESC7 ddesc;
372 char interface_name[] = "WINE Direct3D7 using OpenGL";
373 char device_name[] = "Wine D3D7 device";
375 fill_opengl_caps_7(&ddesc);
377 TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
379 return cb(interface_name, device_name, &ddesc, context);
382 ULONG WINAPI
383 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
385 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
386 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
387 ULONG ref = InterlockedDecrement(&This->ref);
389 TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, ref + 1);
391 if (!ref) {
392 int i;
393 IDirectDrawSurfaceImpl *surface = This->surface, *surf;
395 /* Release texture associated with the device */
396 for (i = 0; i < MAX_TEXTURES; i++) {
397 if (This->current_texture[i] != NULL)
398 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
399 HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
402 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
403 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
404 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
405 surf->aux_ctx = NULL;
406 surf->aux_data = NULL;
407 surf->aux_flip = NULL;
408 break;
411 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
412 IDirectDrawSurfaceImpl *surf2;
413 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
414 for (; surf2 != NULL; surf2 = surf2->next_attached) {
415 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
416 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
417 /* Override the Lock / Unlock function for all these surfaces */
418 surf2->lock_update = surf2->lock_update_prev;
419 surf2->unlock_update = surf2->unlock_update_prev;
420 /* And install also the blt / bltfast overrides */
421 surf2->aux_blt = NULL;
422 surf2->aux_bltfast = NULL;
424 surf2->d3ddevice = NULL;
428 /* And warn the D3D object that this device is no longer active... */
429 This->d3d->d3d_removed_device(This->d3d, This);
431 HeapFree(GetProcessHeap(), 0, This->world_mat);
432 HeapFree(GetProcessHeap(), 0, This->view_mat);
433 HeapFree(GetProcessHeap(), 0, This->proj_mat);
435 if (glThis->surface_ptr)
436 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
438 DeleteCriticalSection(&(This->crit));
440 ENTER_GL();
441 if (glThis->unlock_tex)
442 glDeleteTextures(1, &(glThis->unlock_tex));
443 glXDestroyContext(glThis->display, glThis->gl_context);
444 LEAVE_GL();
445 HeapFree(GetProcessHeap(), 0, This->clipping_planes);
447 HeapFree(GetProcessHeap(), 0, This);
448 return 0;
450 return ref;
453 HRESULT WINAPI
454 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
455 LPD3DDEVICEDESC lpD3DHWDevDesc,
456 LPD3DDEVICEDESC lpD3DHELDevDesc)
458 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
459 D3DDEVICEDESC desc;
460 DWORD dwSize;
462 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
464 fill_opengl_caps(&desc);
465 dwSize = lpD3DHWDevDesc->dwSize;
466 memset(lpD3DHWDevDesc, 0, dwSize);
467 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
469 dwSize = lpD3DHELDevDesc->dwSize;
470 memset(lpD3DHELDevDesc, 0, dwSize);
471 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
473 TRACE(" returning caps : (no dump function yet)\n");
475 return DD_OK;
478 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
479 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
480 LPVOID context, int version)
482 DDSURFACEDESC sdesc;
483 LPDDPIXELFORMAT pformat;
485 /* Do the texture enumeration */
486 sdesc.dwSize = sizeof(DDSURFACEDESC);
487 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
488 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
489 pformat = &(sdesc.ddpfPixelFormat);
490 pformat->dwSize = sizeof(DDPIXELFORMAT);
491 pformat->dwFourCC = 0;
493 TRACE("Enumerating GL_RGBA unpacked (32)\n");
494 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
495 pformat->u1.dwRGBBitCount = 32;
496 pformat->u2.dwRBitMask = 0x00FF0000;
497 pformat->u3.dwGBitMask = 0x0000FF00;
498 pformat->u4.dwBBitMask = 0x000000FF;
499 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
500 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
501 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
503 TRACE("Enumerating GL_RGB unpacked (32)\n");
504 pformat->dwFlags = DDPF_RGB;
505 pformat->u1.dwRGBBitCount = 32;
506 pformat->u2.dwRBitMask = 0x00FF0000;
507 pformat->u3.dwGBitMask = 0x0000FF00;
508 pformat->u4.dwBBitMask = 0x000000FF;
509 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
510 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
511 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
513 TRACE("Enumerating GL_RGB unpacked (24)\n");
514 pformat->dwFlags = DDPF_RGB;
515 pformat->u1.dwRGBBitCount = 24;
516 pformat->u2.dwRBitMask = 0x00FF0000;
517 pformat->u3.dwGBitMask = 0x0000FF00;
518 pformat->u4.dwBBitMask = 0x000000FF;
519 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
520 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
521 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
523 /* Note : even if this is an 'emulated' texture format, it needs to be first
524 as some dumb applications seem to rely on that. */
525 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
526 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
527 pformat->u1.dwRGBBitCount = 16;
528 pformat->u2.dwRBitMask = 0x00007C00;
529 pformat->u3.dwGBitMask = 0x000003E0;
530 pformat->u4.dwBBitMask = 0x0000001F;
531 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
532 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
533 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
535 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
536 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
537 pformat->u1.dwRGBBitCount = 16;
538 pformat->u2.dwRBitMask = 0x00000F00;
539 pformat->u3.dwGBitMask = 0x000000F0;
540 pformat->u4.dwBBitMask = 0x0000000F;
541 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
542 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
543 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
545 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
546 pformat->dwFlags = DDPF_RGB;
547 pformat->u1.dwRGBBitCount = 16;
548 pformat->u2.dwRBitMask = 0x0000F800;
549 pformat->u3.dwGBitMask = 0x000007E0;
550 pformat->u4.dwBBitMask = 0x0000001F;
551 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
552 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
553 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
555 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
556 pformat->dwFlags = DDPF_RGB;
557 pformat->u1.dwRGBBitCount = 16;
558 pformat->u2.dwRBitMask = 0x00007C00;
559 pformat->u3.dwGBitMask = 0x000003E0;
560 pformat->u4.dwBBitMask = 0x0000001F;
561 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
562 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
563 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
565 #if 0
566 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
567 find enumerated, others the last one. And both want to have the ARGB one.
569 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
571 /* See argument about the RGBA format for 'packed' texture formats */
572 TRACE("Enumerating GL_RGBA unpacked (32)\n");
573 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
574 pformat->u1.dwRGBBitCount = 32;
575 pformat->u2.dwRBitMask = 0xFF000000;
576 pformat->u3.dwGBitMask = 0x00FF0000;
577 pformat->u4.dwBBitMask = 0x0000FF00;
578 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
579 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
580 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
582 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
583 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
584 pformat->u1.dwRGBBitCount = 16;
585 pformat->u2.dwRBitMask = 0x0000F000;
586 pformat->u3.dwGBitMask = 0x00000F00;
587 pformat->u4.dwBBitMask = 0x000000F0;
588 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
589 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
590 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
592 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
593 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
594 pformat->u1.dwRGBBitCount = 16;
595 pformat->u2.dwRBitMask = 0x0000F800;
596 pformat->u3.dwGBitMask = 0x000007C0;
597 pformat->u4.dwBBitMask = 0x0000003E;
598 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
599 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
600 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
601 #endif
603 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
604 pformat->dwFlags = DDPF_RGB;
605 pformat->u1.dwRGBBitCount = 8;
606 pformat->u2.dwRBitMask = 0x000000E0;
607 pformat->u3.dwGBitMask = 0x0000001C;
608 pformat->u4.dwBBitMask = 0x00000003;
609 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
610 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
611 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
613 TRACE("Enumerating Paletted (8)\n");
614 pformat->dwFlags = DDPF_PALETTEINDEXED8;
615 pformat->u1.dwRGBBitCount = 8;
616 pformat->u2.dwRBitMask = 0x00000000;
617 pformat->u3.dwGBitMask = 0x00000000;
618 pformat->u4.dwBBitMask = 0x00000000;
619 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
620 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
621 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
623 /* DXT textures only exist for devices created from IDirect3D3 and above */
624 if ((version >= 3) && GL_extensions.s3tc_compressed_texture) {
625 TRACE("Enumerating DXT1\n");
626 pformat->dwFlags = DDPF_FOURCC;
627 pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
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 DXT3\n");
632 pformat->dwFlags = DDPF_FOURCC;
633 pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
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;
637 TRACE("Enumerating DXT5\n");
638 pformat->dwFlags = DDPF_FOURCC;
639 pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
640 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
641 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
644 TRACE("End of enumeration\n");
645 return DD_OK;
649 HRESULT
650 d3ddevice_find(IDirectDrawImpl *d3d,
651 LPD3DFINDDEVICESEARCH lpD3DDFS,
652 LPD3DFINDDEVICERESULT lplpD3DDevice)
654 D3DDEVICEDESC desc;
656 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
657 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
658 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
659 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
661 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
662 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
663 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
664 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
665 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
666 TRACE(" no match for this GUID.\n");
667 return DDERR_INVALIDPARAMS;
671 /* Now return our own GUID */
672 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
673 fill_opengl_caps(&desc);
674 lplpD3DDevice->ddHwDesc = desc;
675 lplpD3DDevice->ddSwDesc = desc;
677 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
679 return D3D_OK;
682 HRESULT WINAPI
683 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
684 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
685 LPVOID lpArg)
687 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
688 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
689 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg, This->version);
692 HRESULT WINAPI
693 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
694 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
695 LPVOID lpArg)
697 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
698 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
699 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg, This->version);
702 HRESULT WINAPI
703 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
704 D3DRENDERSTATETYPE dwRenderStateType,
705 DWORD dwRenderState)
707 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
708 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
710 /* Call the render state functions */
711 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
712 set_render_state(This, dwRenderStateType, &This->state_block);
714 return DD_OK;
717 HRESULT WINAPI
718 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
719 D3DRENDERSTATETYPE dwRenderStateType,
720 LPDWORD lpdwRenderState)
722 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
723 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
725 /* Call the render state functions */
726 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
728 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
730 return DD_OK;
733 HRESULT WINAPI
734 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
735 D3DLIGHTSTATETYPE dwLightStateType,
736 LPDWORD lpdwLightState)
738 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
740 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
742 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
743 TRACE("Unexpected Light State Type\n");
744 return DDERR_INVALIDPARAMS;
747 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
748 *lpdwLightState = This->material;
749 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
750 *lpdwLightState = D3DCOLOR_RGB;
751 } else {
752 D3DRENDERSTATETYPE rs;
753 switch (dwLightStateType) {
754 case D3DLIGHTSTATE_AMBIENT: /* 2 */
755 rs = D3DRENDERSTATE_AMBIENT;
756 break;
757 case D3DLIGHTSTATE_FOGMODE: /* 4 */
758 rs = D3DRENDERSTATE_FOGVERTEXMODE;
759 break;
760 case D3DLIGHTSTATE_FOGSTART: /* 5 */
761 rs = D3DRENDERSTATE_FOGSTART;
762 break;
763 case D3DLIGHTSTATE_FOGEND: /* 6 */
764 rs = D3DRENDERSTATE_FOGEND;
765 break;
766 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
767 rs = D3DRENDERSTATE_FOGDENSITY;
768 break;
769 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
770 rs = D3DRENDERSTATE_COLORVERTEX;
771 break;
772 default:
773 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
774 return DDERR_INVALIDPARAMS;
777 IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
778 rs,lpdwLightState);
781 return DD_OK;
784 HRESULT WINAPI
785 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
786 D3DLIGHTSTATETYPE dwLightStateType,
787 DWORD dwLightState)
789 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
791 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
793 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
794 TRACE("Unexpected Light State Type\n");
795 return DDERR_INVALIDPARAMS;
798 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
799 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
801 if (mat != NULL) {
802 TRACE(" activating material %p.\n", mat);
803 mat->activate(mat);
804 } else {
805 FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
807 This->material = dwLightState;
808 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
809 switch (dwLightState) {
810 case D3DCOLOR_MONO:
811 ERR("DDCOLOR_MONO should not happen!\n");
812 break;
813 case D3DCOLOR_RGB:
814 /* We are already in this mode */
815 TRACE("Setting color model to RGB (no-op).\n");
816 break;
817 default:
818 ERR("Unknown color model!\n");
819 return DDERR_INVALIDPARAMS;
821 } else {
822 D3DRENDERSTATETYPE rs;
823 switch (dwLightStateType) {
824 case D3DLIGHTSTATE_AMBIENT: /* 2 */
825 rs = D3DRENDERSTATE_AMBIENT;
826 break;
827 case D3DLIGHTSTATE_FOGMODE: /* 4 */
828 rs = D3DRENDERSTATE_FOGVERTEXMODE;
829 break;
830 case D3DLIGHTSTATE_FOGSTART: /* 5 */
831 rs = D3DRENDERSTATE_FOGSTART;
832 break;
833 case D3DLIGHTSTATE_FOGEND: /* 6 */
834 rs = D3DRENDERSTATE_FOGEND;
835 break;
836 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
837 rs = D3DRENDERSTATE_FOGDENSITY;
838 break;
839 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
840 rs = D3DRENDERSTATE_COLORVERTEX;
841 break;
842 default:
843 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
844 return DDERR_INVALIDPARAMS;
847 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
848 rs,dwLightState);
851 return DD_OK;
854 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
856 switch (d3dpt) {
857 case D3DPT_POINTLIST:
858 TRACE(" primitive type is POINTS\n");
859 return GL_POINTS;
861 case D3DPT_LINELIST:
862 TRACE(" primitive type is LINES\n");
863 return GL_LINES;
865 case D3DPT_LINESTRIP:
866 TRACE(" primitive type is LINE_STRIP\n");
867 return GL_LINE_STRIP;
869 case D3DPT_TRIANGLELIST:
870 TRACE(" primitive type is TRIANGLES\n");
871 return GL_TRIANGLES;
873 case D3DPT_TRIANGLESTRIP:
874 TRACE(" primitive type is TRIANGLE_STRIP\n");
875 return GL_TRIANGLE_STRIP;
877 case D3DPT_TRIANGLEFAN:
878 TRACE(" primitive type is TRIANGLE_FAN\n");
879 return GL_TRIANGLE_FAN;
881 default:
882 FIXME("Unhandled primitive %08x\n", d3dpt);
883 return GL_POINTS;
887 /* This function calculate the Z coordinate from Zproj */
888 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
890 float a,b,c,d;
891 /* Assume that X = Y = 0 and W = 1 */
892 a = This->proj_mat->_33;
893 b = This->proj_mat->_34;
894 c = This->proj_mat->_43;
895 d = This->proj_mat->_44;
896 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
897 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
898 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
900 return (d*Zproj - c) / (a - b*Zproj);
903 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
904 int i;
906 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
908 for (i = 0; i < 3; i++) {
909 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
910 DWORD elt;
911 for (elt = 0; elt < 0x10000; elt++) {
912 /* We apply the fog transformation and cache the result */
913 DWORD fog_intensity = elt & 0xFF;
914 DWORD vertex_color = (elt >> 8) & 0xFF;
915 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
920 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
921 BOOLEAN vertex_transformed,
922 BOOLEAN vertex_lit) {
923 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
925 /* Puts GL in the correct lighting / transformation mode */
926 if ((vertex_transformed == FALSE) &&
927 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
928 /* Need to put the correct transformation again if we go from Transformed
929 vertices to non-transformed ones.
931 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
932 This->world_mat, This->view_mat, This->proj_mat);
933 glThis->transform_state = GL_TRANSFORM_NORMAL;
935 } else if (vertex_transformed &&
936 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
937 /* Set our orthographic projection */
938 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
939 glThis->transform_state = GL_TRANSFORM_ORTHO;
940 d3ddevice_set_ortho(This);
944 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
945 if no fogging state change occurred */
946 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
947 if (vertex_transformed) {
948 if (glThis->fogging != 0) {
949 glDisable(GL_FOG);
950 glThis->fogging = 0;
952 /* Now check if our fog_table still corresponds to the current vertex color.
953 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
954 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
955 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
956 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
957 /* We need to rebuild our fog table.... */
958 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
960 } else {
961 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
962 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
963 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
964 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
965 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
967 if (vertex_lit == FALSE) {
968 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
969 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
970 } else {
971 /* Special case of 'pixel fog' */
972 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
973 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
975 if (glThis->fogging == 0) {
976 glEnable(GL_FOG);
977 glThis->fogging = 1;
979 } else {
980 if (glThis->fogging != 0) {
981 glDisable(GL_FOG);
982 glThis->fogging = 0;
986 } else {
987 if (glThis->fogging != 0) {
988 glDisable(GL_FOG);
989 glThis->fogging = 0;
993 /* Handle the 'no-normal' case */
994 if ((vertex_lit == FALSE) && This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1]) {
995 if (glThis->lighting == 0) {
996 glEnable(GL_LIGHTING);
997 glThis->lighting = 1;
999 } else {
1000 if (glThis->lighting != 0) {
1001 glDisable(GL_LIGHTING);
1002 glThis->lighting = 0;
1006 /* Handle the code for pre-vertex material properties */
1007 if (vertex_transformed == FALSE) {
1008 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1009 This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1010 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1011 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1012 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1013 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1014 glEnable(GL_COLOR_MATERIAL);
1021 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1022 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1024 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1026 switch (d3dvt) {
1027 case D3DVT_VERTEX: {
1028 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1029 strided.position.dwStride = sizeof(D3DVERTEX);
1030 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1031 strided.normal.dwStride = sizeof(D3DVERTEX);
1032 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1033 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1034 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1035 } break;
1037 case D3DVT_LVERTEX: {
1038 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1039 strided.position.dwStride = sizeof(D3DLVERTEX);
1040 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1041 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1042 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1043 strided.specular.dwStride = sizeof(D3DLVERTEX);
1044 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1045 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1046 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1047 } break;
1049 case D3DVT_TLVERTEX: {
1050 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1051 strided.position.dwStride = sizeof(D3DTLVERTEX);
1052 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1053 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1054 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1055 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1056 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1057 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1058 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1059 } break;
1061 default:
1062 FIXME("Unhandled vertex type %08x\n", d3dvt);
1063 break;
1067 HRESULT WINAPI
1068 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1069 D3DPRIMITIVETYPE d3dptPrimitiveType,
1070 D3DVERTEXTYPE d3dvtVertexType,
1071 LPVOID lpvVertices,
1072 DWORD dwVertexCount,
1073 DWORD dwFlags)
1075 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1077 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1078 if (TRACE_ON(ddraw)) {
1079 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1082 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1084 return DD_OK;
1087 HRESULT WINAPI
1088 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1089 D3DPRIMITIVETYPE d3dptPrimitiveType,
1090 D3DVERTEXTYPE d3dvtVertexType,
1091 LPVOID lpvVertices,
1092 DWORD dwVertexCount,
1093 LPWORD dwIndices,
1094 DWORD dwIndexCount,
1095 DWORD dwFlags)
1097 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1098 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1099 if (TRACE_ON(ddraw)) {
1100 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1103 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1105 return DD_OK;
1108 HRESULT WINAPI
1109 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1110 LPD3DEXECUTEBUFFERDESC lpDesc,
1111 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1112 IUnknown* pUnkOuter)
1114 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1115 IDirect3DExecuteBufferImpl *ret;
1116 HRESULT ret_value;
1118 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1120 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1121 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1123 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1125 return ret_value;
1128 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1129 static BOOLEAN first = TRUE;
1130 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1131 unsigned int row;
1132 GLenum type;
1134 if (first) {
1135 MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1136 first = FALSE;
1139 TRACE("flushing ZBuffer back to GL\n");
1141 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1142 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1143 d3ddevice_set_ortho(d3d_dev);
1146 glMatrixMode(GL_MODELVIEW);
1147 glLoadIdentity();
1149 if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1150 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1151 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1153 /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1154 in some drivers...
1156 switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1157 case 16: type = GL_UNSIGNED_SHORT; break;
1158 case 32: type = GL_UNSIGNED_INT; break;
1159 default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1162 for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1163 /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1164 glRasterPos2i(0, row + 1);
1165 glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1166 ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1169 restore_state:
1170 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1171 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1172 glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1173 if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1176 /* These are the various handler used in the generic path */
1177 inline static void handle_xyz(D3DVALUE *coords) {
1178 glVertex3fv(coords);
1180 inline static void handle_xyzrhw(D3DVALUE *coords) {
1181 if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1182 glVertex3fv(coords);
1183 else {
1184 GLfloat w = 1.0 / coords[3];
1186 glVertex4f(coords[0] * w,
1187 coords[1] * w,
1188 coords[2] * w,
1192 inline static void handle_normal(D3DVALUE *coords) {
1193 glNormal3fv(coords);
1196 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1197 if (sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] ||
1198 sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1]) {
1199 glColor4ub((*color >> 16) & 0xFF,
1200 (*color >> 8) & 0xFF,
1201 (*color >> 0) & 0xFF,
1202 (*color >> 24) & 0xFF);
1203 } else {
1204 glColor3ub((*color >> 16) & 0xFF,
1205 (*color >> 8) & 0xFF,
1206 (*color >> 0) & 0xFF);
1210 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1211 glColor4ub((*color >> 16) & 0xFF,
1212 (*color >> 8) & 0xFF,
1213 (*color >> 0) & 0xFF,
1214 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1217 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1218 if ((lighted == FALSE) &&
1219 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1220 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1221 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1222 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1223 handle_diffuse_base(sb, color);
1225 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1226 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1227 handle_diffuse_base(sb, color);
1229 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1230 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1231 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1232 handle_diffuse_base(sb, color);
1234 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1235 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1236 handle_diffuse_base(sb, color);
1238 } else {
1239 handle_diffuse_base(sb, color);
1243 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1244 if ((lighted == FALSE) &&
1245 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1246 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1247 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1248 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1249 handle_specular_base(sb, color);
1251 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1252 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1253 handle_specular_base(sb, color);
1255 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1256 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1257 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1258 handle_specular_base(sb, color);
1260 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1261 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1262 handle_specular_base(sb, color);
1265 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1268 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1269 if (lighted) {
1270 DWORD color = *color_d;
1271 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
1272 /* Special case where the specular value is used to do fogging */
1273 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1274 color &= 0xFF000000; /* Only keep the alpha component */
1275 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1276 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1277 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1279 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1280 /* Standard specular value in transformed mode. TODO */
1282 handle_diffuse_base(sb, &color);
1283 } else {
1284 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1285 handle_diffuse(sb, color_d, FALSE);
1286 handle_specular(sb, color_s, FALSE);
1287 } else {
1288 /* In that case, only put the diffuse color... */
1289 handle_diffuse_base(sb, color_d);
1294 inline static void handle_texture(D3DVALUE *coords) {
1295 glTexCoord2fv(coords);
1297 inline static void handle_textures(const D3DVALUE *coords, int tex_stage) {
1298 if (GL_extensions.glMultiTexCoord2fv) {
1299 GL_extensions.glMultiTexCoord2fv(GL_TEXTURE0_WINE + tex_stage, coords);
1300 } else {
1301 if (tex_stage == 0) glTexCoord2fv(coords);
1305 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1306 D3DPRIMITIVETYPE d3dptPrimitiveType,
1307 DWORD d3dvtVertexType,
1308 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1309 DWORD dwVertexCount,
1310 LPWORD dwIndices,
1311 DWORD dwIndexCount,
1312 DWORD dwFlags)
1314 BOOLEAN vertex_lighted = FALSE;
1315 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1316 int num_active_stages = 0;
1317 int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
1319 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1320 if (TRACE_ON(ddraw)) {
1321 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1324 /* This is to prevent 'thread contention' between a thread locking the device and another
1325 doing 3D display on it... */
1326 EnterCriticalSection(&(This->crit));
1328 ENTER_GL();
1329 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1330 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1332 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1334 if (This->current_zbuffer == NULL) {
1335 /* Search for an attached ZBuffer */
1336 static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1337 LPDIRECTDRAWSURFACE7 zbuf;
1338 HRESULT hr;
1340 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1341 (DDSCAPS2 *) &zbuf_caps, &zbuf);
1342 if (!FAILED(hr)) {
1343 This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1344 IDirectDrawSurface7_Release(zbuf);
1347 if (This->current_zbuffer != NULL) {
1348 if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1349 flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1353 if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1354 ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1355 vertex_lighted = TRUE;
1357 /* Compute the number of active texture stages and set the various texture parameters */
1358 num_active_stages = draw_primitive_handle_textures(This);
1360 /* And restore to handle '0' in the case we use glTexCoord calls */
1361 if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1362 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1363 glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1366 draw_primitive_handle_GL_state(This,
1367 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1368 vertex_lighted);
1370 /* First, see if we can use the OpenGL vertex arrays... This is very limited
1371 for now to some 'special' cases where we can do a direct mapping between D3D
1372 types and GL types.
1374 Note: in the future all calls will go through vertex arrays but the arrays
1375 will be generated by this function.
1377 Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1378 (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1379 which, as we are little indian, gives a B, G, R, A storage in memory.
1381 if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1382 ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1383 int tex_stage;
1384 TRACE(" using GL vertex arrays for performance !\n");
1385 /* First, the vertices (we are sure we have some :-) */
1386 glEnableClientState(GL_VERTEX_ARRAY);
1387 glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1388 /* Then the normals */
1389 if (d3dvtVertexType & D3DFVF_NORMAL) {
1390 glEnableClientState(GL_NORMAL_ARRAY);
1391 glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1393 /* Then the diffuse colour */
1394 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1395 glEnableClientState(GL_COLOR_ARRAY);
1396 glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1397 ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1399 /* Then the various textures */
1400 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1401 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1402 if (tex_index >= num_tex_index) {
1403 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1404 tex_index = num_tex_index - 1;
1406 if (GL_extensions.glClientActiveTexture) {
1407 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1409 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1410 glTexCoordPointer(2, GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1411 lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1413 if (dwIndices != NULL) {
1414 glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1415 } else {
1416 glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1418 glDisableClientState(GL_VERTEX_ARRAY);
1419 if (d3dvtVertexType & D3DFVF_NORMAL) {
1420 glDisableClientState(GL_NORMAL_ARRAY);
1422 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1423 glDisableClientState(GL_COLOR_ARRAY);
1425 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1426 if (GL_extensions.glClientActiveTexture) {
1427 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1429 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1431 } else {
1432 glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1434 /* Some fast paths first before the generic case.... */
1435 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1436 unsigned int index;
1438 for (index = 0; index < dwIndexCount; index++) {
1439 int i = (dwIndices == NULL) ? index : dwIndices[index];
1440 D3DVALUE *normal =
1441 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1442 D3DVALUE *tex_coord =
1443 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1444 D3DVALUE *position =
1445 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1447 handle_normal(normal);
1448 handle_texture(tex_coord);
1449 handle_xyz(position);
1451 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1452 position[0], position[1], position[2],
1453 normal[0], normal[1], normal[2],
1454 tex_coord[0], tex_coord[1]);
1456 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1457 unsigned int index;
1459 for (index = 0; index < dwIndexCount; index++) {
1460 int i = (dwIndices == NULL) ? index : dwIndices[index];
1461 DWORD *color_d =
1462 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1463 DWORD *color_s =
1464 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1465 D3DVALUE *tex_coord =
1466 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1467 D3DVALUE *position =
1468 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1470 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1471 handle_texture(tex_coord);
1472 handle_xyzrhw(position);
1474 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1475 position[0], position[1], position[2], position[3],
1476 (*color_d >> 16) & 0xFF,
1477 (*color_d >> 8) & 0xFF,
1478 (*color_d >> 0) & 0xFF,
1479 (*color_d >> 24) & 0xFF,
1480 (*color_s >> 16) & 0xFF,
1481 (*color_s >> 8) & 0xFF,
1482 (*color_s >> 0) & 0xFF,
1483 (*color_s >> 24) & 0xFF,
1484 tex_coord[0], tex_coord[1]);
1486 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1487 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1488 /* This is the 'slow path' but that should support all possible vertex formats out there...
1489 Note that people should write a fast path for all vertex formats out there...
1491 unsigned int index;
1492 static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
1494 for (index = 0; index < dwIndexCount; index++) {
1495 int i = (dwIndices == NULL) ? index : dwIndices[index];
1496 int tex_stage;
1498 if (d3dvtVertexType & D3DFVF_NORMAL) {
1499 D3DVALUE *normal =
1500 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1501 handle_normal(normal);
1503 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1504 DWORD *color_d =
1505 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1506 DWORD *color_s =
1507 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1508 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1509 } else {
1510 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1511 DWORD *color_s =
1512 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1513 handle_specular(&(This->state_block), color_s, vertex_lighted);
1514 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1515 DWORD *color_d =
1516 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1517 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1521 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1522 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1523 if (tex_index >= num_tex_index) {
1524 handle_textures((const D3DVALUE *) no_index, tex_stage);
1525 } else {
1526 D3DVALUE *tex_coord =
1527 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1528 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1529 handle_textures(tex_coord, tex_stage);
1533 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1534 D3DVALUE *position =
1535 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1536 handle_xyz(position);
1537 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1538 D3DVALUE *position =
1539 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1540 handle_xyzrhw(position);
1543 if (TRACE_ON(ddraw_geom)) {
1544 unsigned int tex_index;
1546 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1547 D3DVALUE *position =
1548 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1549 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1550 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1551 D3DVALUE *position =
1552 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1553 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1555 if (d3dvtVertexType & D3DFVF_NORMAL) {
1556 D3DVALUE *normal =
1557 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1558 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1560 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1561 DWORD *color_d =
1562 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1563 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1564 (*color_d >> 16) & 0xFF,
1565 (*color_d >> 8) & 0xFF,
1566 (*color_d >> 0) & 0xFF,
1567 (*color_d >> 24) & 0xFF);
1569 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1570 DWORD *color_s =
1571 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1572 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1573 (*color_s >> 16) & 0xFF,
1574 (*color_s >> 8) & 0xFF,
1575 (*color_s >> 0) & 0xFF,
1576 (*color_s >> 24) & 0xFF);
1578 for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
1579 D3DVALUE *tex_coord =
1580 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1581 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1582 TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
1584 TRACE_(ddraw_geom)("\n");
1587 } else {
1588 ERR(" matrix weighting not handled yet....\n");
1591 glEnd();
1594 /* Whatever the case, disable the color material stuff */
1595 glDisable(GL_COLOR_MATERIAL);
1597 LEAVE_GL();
1598 TRACE("End\n");
1600 LeaveCriticalSection(&(This->crit));
1603 HRESULT WINAPI
1604 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1605 D3DPRIMITIVETYPE d3dptPrimitiveType,
1606 DWORD d3dvtVertexType,
1607 LPVOID lpvVertices,
1608 DWORD dwVertexCount,
1609 DWORD dwFlags)
1611 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1612 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1614 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1615 if (TRACE_ON(ddraw)) {
1616 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1619 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1620 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1622 return DD_OK;
1625 HRESULT WINAPI
1626 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1627 D3DPRIMITIVETYPE d3dptPrimitiveType,
1628 DWORD d3dvtVertexType,
1629 LPVOID lpvVertices,
1630 DWORD dwVertexCount,
1631 LPWORD dwIndices,
1632 DWORD dwIndexCount,
1633 DWORD dwFlags)
1635 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1636 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1638 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1639 if (TRACE_ON(ddraw)) {
1640 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1643 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1644 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1646 return DD_OK;
1649 HRESULT WINAPI
1650 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1651 D3DPRIMITIVETYPE d3dptPrimitiveType,
1652 DWORD dwVertexType,
1653 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1654 DWORD dwVertexCount,
1655 DWORD dwFlags)
1657 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1659 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1660 if (TRACE_ON(ddraw)) {
1661 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1663 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1665 return DD_OK;
1668 HRESULT WINAPI
1669 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1670 D3DPRIMITIVETYPE d3dptPrimitiveType,
1671 DWORD dwVertexType,
1672 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1673 DWORD dwVertexCount,
1674 LPWORD lpIndex,
1675 DWORD dwIndexCount,
1676 DWORD dwFlags)
1678 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1680 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1681 if (TRACE_ON(ddraw)) {
1682 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1685 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1687 return DD_OK;
1690 HRESULT WINAPI
1691 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1692 D3DPRIMITIVETYPE d3dptPrimitiveType,
1693 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1694 DWORD dwStartVertex,
1695 DWORD dwNumVertices,
1696 DWORD dwFlags)
1698 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1699 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1700 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1702 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1703 if (TRACE_ON(ddraw)) {
1704 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1707 if (vb_impl->processed) {
1708 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1709 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1711 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1712 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1713 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1715 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1716 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1718 } else {
1719 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1720 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1723 return DD_OK;
1726 HRESULT WINAPI
1727 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1728 D3DPRIMITIVETYPE d3dptPrimitiveType,
1729 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1730 DWORD dwStartVertex,
1731 DWORD dwNumVertices,
1732 LPWORD lpwIndices,
1733 DWORD dwIndexCount,
1734 DWORD dwFlags)
1736 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1737 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1738 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1740 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1741 if (TRACE_ON(ddraw)) {
1742 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1745 if (vb_impl->processed) {
1746 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1747 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1749 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1750 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1751 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1753 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1754 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1756 } else {
1757 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1758 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1761 return DD_OK;
1764 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1765 static BOOLEAN
1766 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1768 BOOLEAN is_complement = FALSE;
1769 BOOLEAN is_alpha_replicate = FALSE;
1770 BOOLEAN handled = TRUE;
1771 GLenum src;
1772 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1773 int num;
1775 if (is_color) {
1776 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1777 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1778 else {
1779 handled = FALSE;
1780 num = 0;
1782 if (tex_op == D3DTOP_SELECTARG2) {
1783 num = 1 - num;
1785 } else {
1786 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1787 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1788 else {
1789 handled = FALSE;
1790 num = 0;
1792 if (tex_op == D3DTOP_SELECTARG2) {
1793 num = 1 - num;
1797 if (dwState & D3DTA_COMPLEMENT) {
1798 is_complement = TRUE;
1800 if (dwState & D3DTA_ALPHAREPLICATE) {
1801 is_alpha_replicate = TRUE;
1803 dwState &= D3DTA_SELECTMASK;
1804 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1805 dwState = D3DTA_DIFFUSE;
1808 switch (dwState) {
1809 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1810 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1811 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1812 case D3DTA_TFACTOR: {
1813 /* Get the constant value from the current rendering state */
1814 GLfloat color[4];
1815 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1817 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1818 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1819 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1820 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1821 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1823 src = GL_CONSTANT_EXT;
1824 } break;
1825 default: src = GL_TEXTURE; handled = FALSE; break;
1828 if (is_color) {
1829 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1830 if (is_alpha_replicate) {
1831 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1832 } else {
1833 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1835 } else {
1836 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1837 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1840 return handled;
1843 HRESULT WINAPI
1844 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1845 DWORD dwStage,
1846 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1847 DWORD dwState)
1849 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1850 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1851 const char *type;
1852 DWORD prev_state;
1853 GLenum unit;
1855 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1857 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1858 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1859 return DD_OK;
1862 unit = GL_TEXTURE0_WINE + dwStage;
1863 if (unit != glThis->current_active_tex_unit) {
1864 GL_extensions.glActiveTexture(unit);
1865 glThis->current_active_tex_unit = unit;
1868 switch (d3dTexStageStateType) {
1869 #define GEN_CASE(a) case a: type = #a; break
1870 GEN_CASE(D3DTSS_COLOROP);
1871 GEN_CASE(D3DTSS_COLORARG1);
1872 GEN_CASE(D3DTSS_COLORARG2);
1873 GEN_CASE(D3DTSS_ALPHAOP);
1874 GEN_CASE(D3DTSS_ALPHAARG1);
1875 GEN_CASE(D3DTSS_ALPHAARG2);
1876 GEN_CASE(D3DTSS_BUMPENVMAT00);
1877 GEN_CASE(D3DTSS_BUMPENVMAT01);
1878 GEN_CASE(D3DTSS_BUMPENVMAT10);
1879 GEN_CASE(D3DTSS_BUMPENVMAT11);
1880 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1881 GEN_CASE(D3DTSS_ADDRESS);
1882 GEN_CASE(D3DTSS_ADDRESSU);
1883 GEN_CASE(D3DTSS_ADDRESSV);
1884 GEN_CASE(D3DTSS_BORDERCOLOR);
1885 GEN_CASE(D3DTSS_MAGFILTER);
1886 GEN_CASE(D3DTSS_MINFILTER);
1887 GEN_CASE(D3DTSS_MIPFILTER);
1888 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1889 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1890 GEN_CASE(D3DTSS_MAXANISOTROPY);
1891 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1892 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1893 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1894 #undef GEN_CASE
1895 default: type = "UNKNOWN";
1898 /* Store the values in the state array */
1899 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1900 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1901 /* Some special cases when one state modifies more than one... */
1902 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1903 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1904 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1907 ENTER_GL();
1909 switch (d3dTexStageStateType) {
1910 case D3DTSS_MINFILTER:
1911 case D3DTSS_MIPFILTER:
1912 if (TRACE_ON(ddraw)) {
1913 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1914 switch ((D3DTEXTUREMINFILTER) dwState) {
1915 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1916 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1917 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1919 } else {
1920 switch ((D3DTEXTUREMIPFILTER) dwState) {
1921 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1922 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1923 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1924 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1928 break;
1930 case D3DTSS_MAGFILTER:
1931 if (TRACE_ON(ddraw)) {
1932 switch ((D3DTEXTUREMAGFILTER) dwState) {
1933 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1934 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1935 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1938 break;
1940 case D3DTSS_ADDRESS:
1941 case D3DTSS_ADDRESSU:
1942 case D3DTSS_ADDRESSV: {
1943 switch ((D3DTEXTUREADDRESS) dwState) {
1944 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1945 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1946 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1947 case D3DTADDRESS_MIRROR:
1948 if (GL_extensions.mirrored_repeat) {
1949 TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1950 } else {
1951 FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1953 break;
1954 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1956 } break;
1958 case D3DTSS_ALPHAOP:
1959 case D3DTSS_COLOROP: {
1960 int scale = 1;
1961 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1962 const char *value;
1963 int handled = 1;
1965 switch (dwState) {
1966 #define GEN_CASE(a) case a: value = #a; break
1967 GEN_CASE(D3DTOP_DISABLE);
1968 GEN_CASE(D3DTOP_SELECTARG1);
1969 GEN_CASE(D3DTOP_SELECTARG2);
1970 GEN_CASE(D3DTOP_MODULATE);
1971 GEN_CASE(D3DTOP_MODULATE2X);
1972 GEN_CASE(D3DTOP_MODULATE4X);
1973 GEN_CASE(D3DTOP_ADD);
1974 GEN_CASE(D3DTOP_ADDSIGNED);
1975 GEN_CASE(D3DTOP_ADDSIGNED2X);
1976 GEN_CASE(D3DTOP_SUBTRACT);
1977 GEN_CASE(D3DTOP_ADDSMOOTH);
1978 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1979 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
1980 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
1981 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
1982 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
1983 GEN_CASE(D3DTOP_PREMODULATE);
1984 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
1985 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
1986 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
1987 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
1988 GEN_CASE(D3DTOP_BUMPENVMAP);
1989 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
1990 GEN_CASE(D3DTOP_DOTPRODUCT3);
1991 GEN_CASE(D3DTOP_FORCE_DWORD);
1992 #undef GEN_CASE
1993 default: value = "UNKNOWN";
1996 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
1997 glDisable(GL_TEXTURE_2D);
1998 TRACE(" disabling 2D texturing.\n");
1999 } else {
2000 /* Re-enable texturing only if COLOROP was not already disabled... */
2001 if ((glThis->current_bound_texture[dwStage] != NULL) &&
2002 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2003 glEnable(GL_TEXTURE_2D);
2004 TRACE(" enabling 2D texturing.\n");
2007 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2008 if ((dwState != D3DTOP_DISABLE) &&
2009 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2010 if (glThis->current_tex_env != GL_COMBINE_EXT) {
2011 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2012 glThis->current_tex_env = GL_COMBINE_EXT;
2016 /* Now set up the operand correctly */
2017 switch (dwState) {
2018 case D3DTOP_DISABLE:
2019 /* Contrary to the docs, alpha can be disabled when colorop is enabled
2020 and it works, so ignore this op */
2021 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2022 break;
2024 case D3DTOP_SELECTARG1:
2025 case D3DTOP_SELECTARG2:
2026 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2027 break;
2029 case D3DTOP_MODULATE4X:
2030 scale = scale * 2; /* Drop through */
2031 case D3DTOP_MODULATE2X:
2032 scale = scale * 2; /* Drop through */
2033 case D3DTOP_MODULATE:
2034 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2035 break;
2037 case D3DTOP_ADD:
2038 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2039 break;
2041 case D3DTOP_ADDSIGNED2X:
2042 scale = scale * 2; /* Drop through */
2043 case D3DTOP_ADDSIGNED:
2044 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2045 break;
2047 /* For the four blending modes, use the Arg2 parameter */
2048 case D3DTOP_BLENDDIFFUSEALPHA:
2049 case D3DTOP_BLENDTEXTUREALPHA:
2050 case D3DTOP_BLENDFACTORALPHA:
2051 case D3DTOP_BLENDCURRENTALPHA: {
2052 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2054 switch (dwState) {
2055 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2056 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2057 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
2058 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2061 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2062 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2063 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2064 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2065 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2066 } break;
2068 default:
2069 handled = FALSE;
2070 break;
2074 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2075 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2076 /* Switch the arguments if needed... */
2077 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2078 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2079 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2080 dwState);
2081 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2082 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2083 dwState);
2084 } else {
2085 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2086 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2087 dwState);
2088 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2089 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2090 dwState);
2094 if (handled) {
2095 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2096 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2097 } else {
2098 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2100 TRACE(" Stage type is : %s => %s\n", type, value);
2101 } else {
2102 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2104 } break;
2106 case D3DTSS_COLORARG1:
2107 case D3DTSS_COLORARG2:
2108 case D3DTSS_ALPHAARG1:
2109 case D3DTSS_ALPHAARG2: {
2110 const char *value, *value_comp = "", *value_alpha = "";
2111 BOOLEAN handled;
2112 D3DTEXTUREOP tex_op;
2114 switch (dwState & D3DTA_SELECTMASK) {
2115 #define GEN_CASE(a) case a: value = #a; break
2116 GEN_CASE(D3DTA_DIFFUSE);
2117 GEN_CASE(D3DTA_CURRENT);
2118 GEN_CASE(D3DTA_TEXTURE);
2119 GEN_CASE(D3DTA_TFACTOR);
2120 GEN_CASE(D3DTA_SPECULAR);
2121 #undef GEN_CASE
2122 default: value = "UNKNOWN";
2124 if (dwState & D3DTA_COMPLEMENT) {
2125 value_comp = " | D3DTA_COMPLEMENT";
2127 if (dwState & D3DTA_ALPHAREPLICATE) {
2128 value_alpha = " | D3DTA_ALPHAREPLICATE";
2131 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2132 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2133 } else {
2134 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2137 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2139 if (handled) {
2140 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2141 } else {
2142 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2144 } break;
2146 case D3DTSS_MIPMAPLODBIAS: {
2147 D3DVALUE value = *((D3DVALUE *) &dwState);
2148 BOOLEAN handled = TRUE;
2150 if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2151 handled = FALSE;
2153 if (handled) {
2154 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2155 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2156 } else {
2157 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2159 } break;
2161 case D3DTSS_MAXMIPLEVEL:
2162 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2163 break;
2165 case D3DTSS_BORDERCOLOR:
2166 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2167 ((dwState >> 16) & 0xFF),
2168 ((dwState >> 8) & 0xFF),
2169 ((dwState >> 0) & 0xFF),
2170 ((dwState >> 24) & 0xFF));
2171 break;
2173 case D3DTSS_TEXCOORDINDEX: {
2174 BOOLEAN handled = TRUE;
2175 const char *value;
2177 switch (dwState & 0xFFFF0000) {
2178 #define GEN_CASE(a) case a: value = #a; break
2179 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2180 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2181 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2182 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2183 #undef GEN_CASE
2184 default: value = "UNKNOWN";
2186 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2187 handled = FALSE;
2189 if (handled) {
2190 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2191 } else {
2192 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2194 } break;
2196 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2197 const char *projected = "", *value;
2198 BOOLEAN handled = TRUE;
2199 switch (dwState & 0xFF) {
2200 #define GEN_CASE(a) case a: value = #a; break
2201 GEN_CASE(D3DTTFF_DISABLE);
2202 GEN_CASE(D3DTTFF_COUNT1);
2203 GEN_CASE(D3DTTFF_COUNT2);
2204 GEN_CASE(D3DTTFF_COUNT3);
2205 GEN_CASE(D3DTTFF_COUNT4);
2206 #undef GEN_CASE
2207 default: value = "UNKNOWN";
2209 if (dwState & D3DTTFF_PROJECTED) {
2210 projected = " | D3DTTFF_PROJECTED";
2211 handled = FALSE;
2214 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2215 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2218 if (handled) {
2219 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2220 } else {
2221 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2223 } break;
2225 default:
2226 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2227 break;
2230 LEAVE_GL();
2232 return DD_OK;
2235 static DWORD
2236 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2238 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2239 DWORD stage;
2240 BOOLEAN enable_colorkey = FALSE;
2242 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2243 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2244 GLenum unit;
2246 /* If this stage is disabled, no need to go further... */
2247 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2248 break;
2250 /* First check if we need to bind any other texture for this stage */
2251 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2252 if (This->current_texture[stage] == NULL) {
2253 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2255 unit = GL_TEXTURE0_WINE + stage;
2256 if (unit != glThis->current_active_tex_unit) {
2257 GL_extensions.glActiveTexture(unit);
2258 glThis->current_active_tex_unit = unit;
2260 glBindTexture(GL_TEXTURE_2D, 0);
2261 glDisable(GL_TEXTURE_2D);
2262 } else {
2263 GLenum tex_name = gltex_get_tex_name(surf_ptr);
2265 unit = GL_TEXTURE0_WINE + stage;
2266 if (unit != glThis->current_active_tex_unit) {
2267 GL_extensions.glActiveTexture(unit);
2268 glThis->current_active_tex_unit = unit;
2271 if (glThis->current_bound_texture[stage] == NULL) {
2272 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2273 TRACE(" enabling 2D texturing and");
2274 glEnable(GL_TEXTURE_2D);
2277 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2278 glBindTexture(GL_TEXTURE_2D, tex_name);
2281 glThis->current_bound_texture[stage] = This->current_texture[stage];
2282 } else {
2283 if (glThis->current_bound_texture[stage] == NULL) {
2284 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2285 } else {
2286 TRACE(" using already bound texture id %d for stage %ld.\n",
2287 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2291 /* If no texure valid for this stage, go out of the loop */
2292 if (This->current_texture[stage] == NULL) break;
2294 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2295 This will also update the various texture parameters if needed.
2297 gltex_upload_texture(surf_ptr, This, stage);
2299 /* And finally check for color-keying (only on first stage) */
2300 if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2301 if (stage == 0) {
2302 enable_colorkey = TRUE;
2303 } else {
2304 static BOOL warn = FALSE;
2305 if (warn == FALSE) {
2306 warn = TRUE;
2307 WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2310 } else {
2311 if (stage == 0) {
2312 enable_colorkey = FALSE;
2317 /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2318 if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2319 (glThis->parent.version == 1)) &&
2320 (enable_colorkey)) {
2321 TRACE(" colorkey activated.\n");
2323 if (glThis->alpha_test == FALSE) {
2324 glEnable(GL_ALPHA_TEST);
2325 glThis->alpha_test = TRUE;
2327 if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2328 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1]) {
2329 static BOOL warn = FALSE;
2330 if (warn == FALSE) {
2331 warn = TRUE;
2332 WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2335 glThis->current_alpha_test_func = GL_NOTEQUAL;
2336 glThis->current_alpha_test_ref = 0.0;
2337 glAlphaFunc(GL_NOTEQUAL, 0.0);
2339 /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2340 Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2341 } else {
2342 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2343 glDisable(GL_ALPHA_TEST);
2344 glThis->alpha_test = FALSE;
2346 /* Maybe we should restore here the application-given alpha test states ? */
2349 return stage;
2352 HRESULT WINAPI
2353 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2354 DWORD dwStage,
2355 LPDIRECTDRAWSURFACE7 lpTexture2)
2357 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2359 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2361 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2362 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2363 if (lpTexture2 != NULL) {
2364 WARN(" setting a texture to a non-supported texture stage !\n");
2366 return DD_OK;
2369 if (This->current_texture[dwStage] != NULL) {
2370 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2373 if (lpTexture2 == NULL) {
2374 This->current_texture[dwStage] = NULL;
2375 } else {
2376 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2377 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2378 This->current_texture[dwStage] = tex_impl;
2381 return DD_OK;
2384 HRESULT WINAPI
2385 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2386 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2388 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2389 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2391 fill_opengl_caps_7(lpD3DHELDevDesc);
2393 TRACE(" returning caps : no dump function yet.\n");
2395 return DD_OK;
2398 HRESULT WINAPI
2399 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2400 LPD3DMATERIAL7 lpMat)
2402 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2403 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2405 if (TRACE_ON(ddraw)) {
2406 TRACE(" material is : \n");
2407 dump_D3DMATERIAL7(lpMat);
2410 This->current_material = *lpMat;
2412 ENTER_GL();
2413 glMaterialfv(GL_FRONT_AND_BACK,
2414 GL_DIFFUSE,
2415 (float *) &(This->current_material.u.diffuse));
2416 glMaterialfv(GL_FRONT_AND_BACK,
2417 GL_AMBIENT,
2418 (float *) &(This->current_material.u1.ambient));
2419 glMaterialfv(GL_FRONT_AND_BACK,
2420 GL_SPECULAR,
2421 (float *) &(This->current_material.u2.specular));
2422 glMaterialfv(GL_FRONT_AND_BACK,
2423 GL_EMISSION,
2424 (float *) &(This->current_material.u3.emissive));
2425 glMaterialf(GL_FRONT_AND_BACK,
2426 GL_SHININESS,
2427 This->current_material.u4.power); /* Not sure about this... */
2428 LEAVE_GL();
2430 return DD_OK;
2434 HRESULT WINAPI
2435 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2436 DWORD dwLightIndex,
2437 LPD3DLIGHT7 lpLight)
2439 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2440 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2441 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2443 if (TRACE_ON(ddraw)) {
2444 TRACE(" setting light : \n");
2445 dump_D3DLIGHT7(lpLight);
2448 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2449 This->set_lights |= 0x00000001 << dwLightIndex;
2450 This->light_parameters[dwLightIndex] = *lpLight;
2452 /* Some checks to print out nice warnings :-) */
2453 switch (lpLight->dltType) {
2454 case D3DLIGHT_DIRECTIONAL:
2455 case D3DLIGHT_POINT:
2456 /* These are handled properly... */
2457 break;
2459 case D3DLIGHT_SPOT:
2460 if ((lpLight->dvTheta != 0.0) ||
2461 (lpLight->dvTheta != lpLight->dvPhi)) {
2462 ERR("dvTheta not fully supported yet !\n");
2464 break;
2466 default:
2467 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2470 /* This will force the Light setting on next drawing of primitives */
2471 glThis->transform_state = GL_TRANSFORM_NONE;
2473 return DD_OK;
2476 HRESULT WINAPI
2477 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2478 DWORD dwLightIndex,
2479 BOOL bEnable)
2481 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2482 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2484 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2486 ENTER_GL();
2487 if (bEnable) {
2488 if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
2489 /* Set the default parameters.. */
2490 TRACE(" setting default light parameters...\n");
2491 GL_IDirect3DDeviceImpl_7_SetLight(iface, dwLightIndex, &(This->light_parameters[dwLightIndex]));
2493 glEnable(GL_LIGHT0 + dwLightIndex);
2494 if ((This->active_lights & (0x00000001 << dwLightIndex)) == 0) {
2495 /* This light gets active... Need to update its parameters to GL before the next drawing */
2496 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2498 This->active_lights |= 0x00000001 << dwLightIndex;
2499 glThis->transform_state = GL_TRANSFORM_NONE;
2501 } else {
2502 glDisable(GL_LIGHT0 + dwLightIndex);
2503 This->active_lights &= ~(0x00000001 << dwLightIndex);
2505 LEAVE_GL();
2507 return DD_OK;
2510 HRESULT WINAPI
2511 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2513 IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2514 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2516 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2518 if (dwIndex >= This->max_clipping_planes) {
2519 return DDERR_INVALIDPARAMS;
2522 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2524 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2526 /* This is to force the reset of the transformation matrices on the next drawing.
2527 * This is needed to use the correct matrices for the various clipping planes.
2529 glThis->transform_state = GL_TRANSFORM_NONE;
2531 return D3D_OK;
2534 HRESULT WINAPI
2535 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2536 LPD3DVIEWPORT7 lpData)
2538 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2539 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2541 if (TRACE_ON(ddraw)) {
2542 TRACE(" viewport is : \n");
2543 TRACE(" - dwX = %ld dwY = %ld\n",
2544 lpData->dwX, lpData->dwY);
2545 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2546 lpData->dwWidth, lpData->dwHeight);
2547 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2548 lpData->dvMinZ, lpData->dvMaxZ);
2550 ENTER_GL();
2552 /* Set the viewport */
2553 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2554 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2555 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2557 if ((lpData->dwX != This->active_viewport.dwX) ||
2558 (lpData->dwY != This->active_viewport.dwY) ||
2559 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2560 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2561 glViewport(lpData->dwX,
2562 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2563 lpData->dwWidth, lpData->dwHeight);
2566 LEAVE_GL();
2568 This->active_viewport = *lpData;
2570 return DD_OK;
2573 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2574 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2575 #else
2576 # define XCAST(fun) (void*)
2577 #endif
2579 static const IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2581 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2582 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2583 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2584 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2585 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2586 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2587 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2588 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2589 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2590 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2591 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2592 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2593 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2594 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2595 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2596 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2597 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2598 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2599 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2600 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2601 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2602 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2603 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2604 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2605 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2606 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2607 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2608 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2609 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2610 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2611 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2612 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2613 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2614 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2615 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2616 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2617 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2618 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2619 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2620 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2621 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2622 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2623 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2624 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2625 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2626 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2627 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2628 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2629 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2632 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2633 #undef XCAST
2634 #endif
2637 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2638 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2639 #else
2640 # define XCAST(fun) (void*)
2641 #endif
2643 static const IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2645 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2646 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2647 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2648 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2649 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2650 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2651 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2652 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2653 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2654 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2655 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2656 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2657 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2658 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2659 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2660 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2661 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2662 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2663 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2664 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2665 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2666 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2667 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2668 XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2669 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2670 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2671 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2672 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2673 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2674 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2675 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2676 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2677 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2678 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2679 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2680 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2681 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2682 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2683 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2684 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2685 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2686 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2689 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2690 #undef XCAST
2691 #endif
2694 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2695 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2696 #else
2697 # define XCAST(fun) (void*)
2698 #endif
2700 static const IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2702 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2703 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2704 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2705 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2706 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2707 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2708 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2709 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2710 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2711 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2712 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2713 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2714 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2715 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2716 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2717 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2718 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2719 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2720 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2721 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2722 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2723 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2724 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2725 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2726 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2727 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2728 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2729 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2730 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2731 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2732 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2733 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2734 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2737 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2738 #undef XCAST
2739 #endif
2742 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2743 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2744 #else
2745 # define XCAST(fun) (void*)
2746 #endif
2748 static const IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2750 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2751 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2752 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2753 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2754 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2755 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2756 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2757 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2758 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2759 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2760 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2761 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2762 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2763 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2764 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2765 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2766 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2767 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2768 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2769 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2770 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2771 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2774 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2775 #undef XCAST
2776 #endif
2778 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2779 WINE_GL_BUFFER_TYPE buffer_type,
2780 DWORD dwCount,
2781 LPD3DRECT lpRects,
2782 DWORD dwFlags,
2783 DWORD dwColor,
2784 D3DVALUE dvZ,
2785 DWORD dwStencil)
2787 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2788 GLbitfield bitfield = 0;
2789 D3DRECT rect;
2790 unsigned int i;
2792 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2793 if (TRACE_ON(ddraw)) {
2794 if (dwCount > 0) {
2795 unsigned int i;
2796 TRACE(" rectangles : \n");
2797 for (i = 0; i < dwCount; i++) {
2798 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2803 if (dwCount == 0) {
2804 dwCount = 1;
2805 rect.u1.x1 = 0;
2806 rect.u2.y1 = 0;
2807 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2808 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2809 lpRects = &rect;
2812 /* Clears the screen */
2813 ENTER_GL();
2815 if (dwFlags & D3DCLEAR_TARGET) {
2816 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2817 /* TODO: optimize here the case where Clear changes all the screen... */
2818 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2820 glThis->state[buffer_type] = SURFACE_GL;
2823 if (dwFlags & D3DCLEAR_ZBUFFER) {
2824 bitfield |= GL_DEPTH_BUFFER_BIT;
2825 if (glThis->depth_mask == FALSE) {
2826 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2828 if (dvZ != glThis->prev_clear_Z) {
2829 glClearDepth(dvZ);
2830 glThis->prev_clear_Z = dvZ;
2832 TRACE(" depth value : %f\n", dvZ);
2834 if (dwFlags & D3DCLEAR_STENCIL) {
2835 bitfield |= GL_STENCIL_BUFFER_BIT;
2836 if (dwStencil != glThis->prev_clear_stencil) {
2837 glClearStencil(dwStencil);
2838 glThis->prev_clear_stencil = dwStencil;
2840 TRACE(" stencil value : %ld\n", dwStencil);
2842 if (dwFlags & D3DCLEAR_TARGET) {
2843 bitfield |= GL_COLOR_BUFFER_BIT;
2844 if (dwColor != glThis->prev_clear_color) {
2845 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2846 ((dwColor >> 8) & 0xFF) / 255.0,
2847 ((dwColor >> 0) & 0xFF) / 255.0,
2848 ((dwColor >> 24) & 0xFF) / 255.0);
2849 glThis->prev_clear_color = dwColor;
2851 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2854 glEnable(GL_SCISSOR_TEST);
2855 for (i = 0; i < dwCount; i++) {
2856 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2857 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2858 glClear(bitfield);
2860 glDisable(GL_SCISSOR_TEST);
2862 if (dwFlags & D3DCLEAR_ZBUFFER) {
2863 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2866 LEAVE_GL();
2868 return DD_OK;
2871 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2872 DWORD dwCount,
2873 LPD3DRECT lpRects,
2874 DWORD dwFlags,
2875 DWORD dwColor,
2876 D3DVALUE dvZ,
2877 DWORD dwStencil)
2879 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2882 static HRESULT
2883 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2884 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2886 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2887 WINE_GL_BUFFER_TYPE buffer_type;
2889 /* First check if we BLT to the backbuffer... */
2890 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2891 buffer_type = WINE_GL_BUFFER_BACK;
2892 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2893 buffer_type = WINE_GL_BUFFER_FRONT;
2894 } else {
2895 ERR("Only BLT override to front or back-buffer is supported for now !\n");
2896 return DDERR_INVALIDPARAMS;
2899 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
2900 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
2901 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
2902 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
2903 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
2904 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
2905 * GL to do it.
2907 return DDERR_INVALIDPARAMS;
2909 *buffer_type_p = buffer_type;
2911 return DD_OK;
2914 HRESULT
2915 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
2916 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
2917 DWORD dwFlags, LPDDBLTFX lpbltfx)
2919 WINE_GL_BUFFER_TYPE buffer_type;
2920 D3DRECT rect;
2922 if (rdst) {
2923 rect.u1.x1 = rdst->left;
2924 rect.u2.y1 = rdst->top;
2925 rect.u3.x2 = rdst->right;
2926 rect.u4.y2 = rdst->bottom;
2927 } else {
2928 rect.u1.x1 = 0;
2929 rect.u2.y1 = 0;
2930 rect.u3.x2 = This->surface_desc.dwWidth;
2931 rect.u4.y2 = This->surface_desc.dwHeight;
2934 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
2936 if (dwFlags & DDBLT_COLORFILL) {
2937 /* This is easy to handle for the D3D Device... */
2938 DWORD color;
2939 GLenum prev_draw;
2941 /* The color as given in the Blt function is in the format of the frame-buffer...
2942 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2944 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
2945 if (This->palette) {
2946 color = ((0xFF000000) |
2947 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
2948 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
2949 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
2950 } else {
2951 color = 0xFF000000;
2953 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
2954 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
2955 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
2956 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
2957 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
2958 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
2959 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
2960 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
2961 color = 0xFFFFFFFF;
2962 } else {
2963 color = ((0xFF000000) |
2964 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
2965 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
2966 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
2968 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
2969 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
2970 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
2971 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
2972 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
2973 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
2974 } else {
2975 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
2976 return DDERR_INVALIDPARAMS;
2978 } else {
2979 ERR("Wrong surface type for BLT override !\n");
2980 return DDERR_INVALIDPARAMS;
2983 TRACE(" executing D3D Device override.\n");
2985 ENTER_GL();
2987 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2988 if (buffer_type == WINE_GL_BUFFER_FRONT)
2989 glDrawBuffer(GL_FRONT);
2990 else
2991 glDrawBuffer(GL_BACK);
2993 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
2995 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
2996 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
2997 glDrawBuffer(prev_draw);
2999 LEAVE_GL();
3001 return DD_OK;
3002 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
3003 /* Normal blit without any special case... */
3004 if (src != NULL) {
3005 /* And which has a SRC surface */
3006 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3008 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3009 (src_impl->d3ddevice == This->d3ddevice) &&
3010 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3011 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3012 D3DRECT src_rect;
3013 int width, height;
3014 GLenum prev_draw;
3015 WINE_GL_BUFFER_TYPE src_buffer_type;
3016 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3017 BOOLEAN initial;
3018 DWORD opt_bitmap;
3019 int x, y;
3021 if (rsrc) {
3022 src_rect.u1.x1 = rsrc->left;
3023 src_rect.u2.y1 = rsrc->top;
3024 src_rect.u3.x2 = rsrc->right;
3025 src_rect.u4.y2 = rsrc->bottom;
3026 } else {
3027 src_rect.u1.x1 = 0;
3028 src_rect.u2.y1 = 0;
3029 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3030 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3033 width = src_rect.u3.x2 - src_rect.u1.x1;
3034 height = src_rect.u4.y2 - src_rect.u2.y1;
3036 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3037 (height != (rect.u4.y2 - rect.u2.y1))) {
3038 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3039 return DDERR_INVALIDPARAMS;
3042 /* First check if we BLT from the backbuffer... */
3043 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3044 src_buffer_type = WINE_GL_BUFFER_BACK;
3045 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3046 src_buffer_type = WINE_GL_BUFFER_FRONT;
3047 } else {
3048 ERR("Unexpected case in direct buffer to buffer copy !\n");
3049 return DDERR_INVALIDPARAMS;
3052 TRACE(" using direct buffer to buffer copy.\n");
3054 ENTER_GL();
3056 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3058 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3059 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3060 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3061 LEAVE_GL();
3062 return DDERR_INVALIDPARAMS;
3065 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3066 if (buffer_type == WINE_GL_BUFFER_FRONT)
3067 glDrawBuffer(GL_FRONT);
3068 else
3069 glDrawBuffer(GL_BACK);
3071 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3072 glReadBuffer(GL_FRONT);
3073 else
3074 glReadBuffer(GL_BACK);
3076 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3077 And directly re-draws this on the destination buffer. */
3078 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3079 int get_height;
3081 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3082 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3083 else
3084 get_height = UNLOCK_TEX_SIZE;
3086 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3087 int get_width;
3089 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3090 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3091 else
3092 get_width = UNLOCK_TEX_SIZE;
3094 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3095 0, UNLOCK_TEX_SIZE - get_height,
3096 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3097 get_width, get_height);
3099 glBegin(GL_QUADS);
3100 glTexCoord2f(0.0, 0.0);
3101 glVertex3d(rect.u1.x1 + x,
3102 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3103 0.5);
3104 glTexCoord2f(1.0, 0.0);
3105 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3106 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3107 0.5);
3108 glTexCoord2f(1.0, 1.0);
3109 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3110 rect.u2.y1 + y,
3111 0.5);
3112 glTexCoord2f(0.0, 1.0);
3113 glVertex3d(rect.u1.x1 + x,
3114 rect.u2.y1 + y,
3115 0.5);
3116 glEnd();
3120 upload_surface_to_tex_memory_release();
3121 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3123 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3124 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3125 glDrawBuffer(prev_draw);
3127 LEAVE_GL();
3129 return DD_OK;
3130 } else {
3131 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3132 (this prevents calling glReadPixels) */
3133 D3DRECT src_rect;
3134 int width, height;
3135 GLenum prev_draw;
3136 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3137 BOOLEAN initial;
3138 DWORD opt_bitmap;
3139 int x, y;
3140 double x_stretch, y_stretch;
3142 if (rsrc) {
3143 src_rect.u1.x1 = rsrc->left;
3144 src_rect.u2.y1 = rsrc->top;
3145 src_rect.u3.x2 = rsrc->right;
3146 src_rect.u4.y2 = rsrc->bottom;
3147 } else {
3148 src_rect.u1.x1 = 0;
3149 src_rect.u2.y1 = 0;
3150 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3151 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3154 width = src_rect.u3.x2 - src_rect.u1.x1;
3155 height = src_rect.u4.y2 - src_rect.u2.y1;
3157 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3158 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3160 TRACE(" using memory to buffer Blt override.\n");
3162 ENTER_GL();
3164 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3166 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3167 initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3168 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3169 LEAVE_GL();
3170 return DDERR_INVALIDPARAMS;
3173 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3174 if (buffer_type == WINE_GL_BUFFER_FRONT)
3175 glDrawBuffer(GL_FRONT);
3176 else
3177 glDrawBuffer(GL_BACK);
3179 /* Now the serious stuff happens. This is basically the same code as for the memory
3180 flush to frame buffer ... with stretching and different rectangles added :-) */
3181 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3182 RECT flush_rect;
3184 flush_rect.top = src_rect.u2.y1 + y;
3185 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3186 src_rect.u4.y2 :
3187 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3189 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3190 flush_rect.left = src_rect.u1.x1 + x;
3191 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3192 src_rect.u3.x2 :
3193 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3195 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3197 glBegin(GL_QUADS);
3198 glTexCoord2f(0.0, 0.0);
3199 glVertex3d(rect.u1.x1 + (x * x_stretch),
3200 rect.u2.y1 + (y * y_stretch),
3201 0.5);
3202 glTexCoord2f(1.0, 0.0);
3203 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3204 rect.u2.y1 + (y * y_stretch),
3205 0.5);
3206 glTexCoord2f(1.0, 1.0);
3207 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3208 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3209 0.5);
3210 glTexCoord2f(0.0, 1.0);
3211 glVertex3d(rect.u1.x1 + (x * x_stretch),
3212 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3213 0.5);
3214 glEnd();
3218 upload_surface_to_tex_memory_release();
3219 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3221 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3222 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3223 glDrawBuffer(prev_draw);
3225 LEAVE_GL();
3227 return DD_OK;
3231 return DDERR_INVALIDPARAMS;
3234 HRESULT
3235 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3236 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3237 LPRECT rsrc, DWORD trans)
3239 RECT rsrc2;
3240 RECT rdst;
3241 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3242 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3243 WINE_GL_BUFFER_TYPE buffer_type;
3244 GLenum prev_draw;
3245 DWORD opt_bitmap;
3246 BOOLEAN initial;
3247 int width, height, x, y;
3249 /* Cannot support DSTCOLORKEY blitting... */
3250 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3252 if (rsrc == NULL) {
3253 WARN("rsrc is NULL - getting the whole surface !!\n");
3254 rsrc = &rsrc2;
3255 rsrc->left = rsrc->top = 0;
3256 rsrc->right = src_impl->surface_desc.dwWidth;
3257 rsrc->bottom = src_impl->surface_desc.dwHeight;
3258 } else {
3259 rsrc2 = *rsrc;
3260 rsrc = &rsrc2;
3263 rdst.left = dstx;
3264 rdst.top = dsty;
3265 rdst.right = dstx + (rsrc->right - rsrc->left);
3266 if (rdst.right > This->surface_desc.dwWidth) {
3267 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3268 rdst.right = This->surface_desc.dwWidth;
3270 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3271 if (rdst.bottom > This->surface_desc.dwHeight) {
3272 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3273 rdst.bottom = This->surface_desc.dwHeight;
3276 width = rsrc->right - rsrc->left;
3277 height = rsrc->bottom - rsrc->top;
3279 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3281 TRACE(" using BltFast memory to frame buffer override.\n");
3283 ENTER_GL();
3285 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3287 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3288 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3289 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3290 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3291 LEAVE_GL();
3292 return DDERR_INVALIDPARAMS;
3295 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3296 if (buffer_type == WINE_GL_BUFFER_FRONT)
3297 glDrawBuffer(GL_FRONT);
3298 else
3299 glDrawBuffer(GL_BACK);
3301 /* Now the serious stuff happens. This is basically the same code that for the memory
3302 flush to frame buffer but with different rectangles for source and destination :-) */
3303 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3304 RECT flush_rect;
3306 flush_rect.top = rsrc->top + y;
3307 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3308 rsrc->bottom :
3309 (rsrc->top + y + UNLOCK_TEX_SIZE));
3311 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3312 flush_rect.left = rsrc->left + x;
3313 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3314 rsrc->right :
3315 (rsrc->left + x + UNLOCK_TEX_SIZE));
3317 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3319 glBegin(GL_QUADS);
3320 glTexCoord2f(0.0, 0.0);
3321 glVertex3d(rdst.left + x,
3322 rdst.top + y,
3323 0.5);
3324 glTexCoord2f(1.0, 0.0);
3325 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3326 rdst.top + y,
3327 0.5);
3328 glTexCoord2f(1.0, 1.0);
3329 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3330 rdst.top + (y + UNLOCK_TEX_SIZE),
3331 0.5);
3332 glTexCoord2f(0.0, 1.0);
3333 glVertex3d(rdst.left + x,
3334 rdst.top + (y + UNLOCK_TEX_SIZE),
3335 0.5);
3336 glEnd();
3340 upload_surface_to_tex_memory_release();
3341 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3343 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3344 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3345 glDrawBuffer(prev_draw);
3347 LEAVE_GL();
3349 return DD_OK;
3352 void
3353 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3355 GLfloat height, width;
3356 GLfloat trans_mat[16];
3358 TRACE("(%p)\n", This);
3360 width = This->surface->surface_desc.dwWidth;
3361 height = This->surface->surface_desc.dwHeight;
3363 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3364 * to OpenGL screen coordinates (ie the upper left corner is not the same).
3366 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3367 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3368 #if 0
3369 /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3370 * that the Z coordinate needs to be given to GL unchanged.
3372 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 2.0; trans_mat[14] = -1.0;
3373 #endif
3374 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = 0.0;
3375 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3377 ENTER_GL();
3378 glMatrixMode(GL_MODELVIEW);
3379 glLoadIdentity();
3380 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3381 Correctness Tips section).
3383 Basically, from what I understood, if the game does not filter the font texture,
3384 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3385 one and we will have strange artifacts (as the rounding and stuff may give different results
3386 for different pixels, ie sometimes take the left pixel, sometimes the right).
3388 glTranslatef(0.375, 0.375, 0);
3389 glMatrixMode(GL_PROJECTION);
3390 glLoadMatrixf(trans_mat);
3391 LEAVE_GL();
3394 void
3395 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3396 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3398 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3400 ENTER_GL();
3401 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3402 glMatrixMode(GL_MODELVIEW);
3403 glLoadMatrixf((float *) view_mat);
3405 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3406 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3407 GLint i;
3408 DWORD runner;
3409 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3410 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3411 GLdouble plane[4];
3413 plane[0] = This->clipping_planes[i].plane[0];
3414 plane[1] = This->clipping_planes[i].plane[1];
3415 plane[2] = This->clipping_planes[i].plane[2];
3416 plane[3] = This->clipping_planes[i].plane[3];
3418 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3422 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3423 GLint i;
3424 DWORD runner;
3426 for (i = 0, runner = 0x00000001; i < MAX_LIGHTS; i++, runner <<= 1) {
3427 if (runner & This->active_lights) {
3428 switch (This->light_parameters[i].dltType) {
3429 case D3DLIGHT_DIRECTIONAL: {
3430 float direction[4];
3431 float cut_off = 180.0;
3433 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3434 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3435 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3436 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3438 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3439 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3440 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3441 direction[3] = 0.0;
3442 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3443 } break;
3445 case D3DLIGHT_POINT: {
3446 float position[4];
3447 float cut_off = 180.0;
3449 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3450 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3451 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3452 position[0] = This->light_parameters[i].dvPosition.u1.x;
3453 position[1] = This->light_parameters[i].dvPosition.u2.y;
3454 position[2] = This->light_parameters[i].dvPosition.u3.z;
3455 position[3] = 1.0;
3456 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3457 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3458 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3459 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3460 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3461 } break;
3463 case D3DLIGHT_SPOT: {
3464 float direction[4];
3465 float position[4];
3466 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3468 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3469 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3470 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3472 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3473 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3474 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3475 direction[3] = 0.0;
3476 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3477 position[0] = This->light_parameters[i].dvPosition.u1.x;
3478 position[1] = This->light_parameters[i].dvPosition.u2.y;
3479 position[2] = This->light_parameters[i].dvPosition.u3.z;
3480 position[3] = 1.0;
3481 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3482 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3483 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3484 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3485 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3486 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &(This->light_parameters[i].dvFalloff));
3487 } break;
3489 default:
3490 /* No warning here as it's already done at light setting */
3491 break;
3497 glMultMatrixf((float *) world_mat);
3499 if ((matrices & PROJMAT_CHANGED) != 0) {
3500 glMatrixMode(GL_PROJECTION);
3501 glLoadMatrixf((float *) proj_mat);
3503 LEAVE_GL();
3506 void
3507 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3509 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3510 DWORD tex_mat, tex_stage;
3512 TRACE("(%p,%08lx)\n", This, matrices);
3514 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3515 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3516 /* This will force an update of the transform state at the next drawing. */
3517 glThis->transform_state = GL_TRANSFORM_NONE;
3520 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3521 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3523 ENTER_GL();
3524 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3525 GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3526 if (matrices & tex_mat) {
3527 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3528 int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3530 if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3531 if (glThis->current_active_tex_unit != unit) {
3532 GL_extensions.glActiveTexture(unit);
3533 glThis->current_active_tex_unit = unit;
3535 glMatrixMode(GL_TEXTURE);
3536 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3538 This->tex_mat_is_identity[tex_stage] = is_identity;
3539 } else {
3540 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3541 if (glThis->current_active_tex_unit != unit) {
3542 GL_extensions.glActiveTexture(unit);
3543 glThis->current_active_tex_unit = unit;
3545 glMatrixMode(GL_TEXTURE);
3546 glLoadIdentity();
3547 This->tex_mat_is_identity[tex_stage] = TRUE;
3552 LEAVE_GL();
3556 /* TODO for both these functions :
3557 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3558 by other OpenGL code in D3D
3559 - handle the case where no 'Begin / EndScene' was done between two locks
3560 - handle the rectangles in the unlock too
3561 - handle pitch correctly...
3563 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3565 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3566 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3567 WINE_GL_BUFFER_TYPE buffer_type;
3568 RECT loc_rect;
3570 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3571 buffer_type = WINE_GL_BUFFER_FRONT;
3572 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3573 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3574 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3576 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3577 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3578 buffer_type = WINE_GL_BUFFER_BACK;
3579 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3580 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3581 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3583 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3584 } else {
3585 ERR("Wrong surface type for locking !\n");
3586 return;
3589 if (pRect == NULL) {
3590 loc_rect.top = 0;
3591 loc_rect.left = 0;
3592 loc_rect.bottom = This->surface_desc.dwHeight;
3593 loc_rect.right = This->surface_desc.dwWidth;
3594 pRect = &loc_rect;
3597 /* Try to acquire the device critical section */
3598 EnterCriticalSection(&(d3d_dev->crit));
3600 if (gl_d3d_dev->lock_rect_valid[buffer_type]) {
3601 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3602 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3604 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3606 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3607 /* Check if the new rectangle is in the previous one or not.
3608 If it is not, flush first the previous locks on screen.
3610 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3611 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3612 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3613 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3614 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3615 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3616 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3617 pRect->left, pRect->top, pRect->right, pRect->bottom,
3618 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3619 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3620 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3622 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3623 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3625 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3626 } else {
3627 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3630 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3631 /* If the surface is already in memory, no need to do anything here... */
3632 GLenum buffer_format;
3633 GLenum buffer_color;
3634 int y;
3635 char *dst;
3637 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3638 pRect->left, pRect->top, pRect->right, pRect->bottom);
3640 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3641 may only write to the device... But when we will blit it back to the screen, we need
3642 also to blit correctly the parts the application did not overwrite... */
3644 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3645 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3646 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3647 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3648 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3649 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3650 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3651 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3652 buffer_color = GL_RGB;
3653 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3654 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3655 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3656 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3657 buffer_format = GL_UNSIGNED_BYTE;
3658 buffer_color = GL_RGB;
3659 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3660 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3661 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3662 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3663 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3664 buffer_color = GL_BGRA;
3665 } else {
3666 ERR(" unsupported pixel format at device locking.\n");
3667 return;
3669 } else {
3670 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3671 return;
3674 ENTER_GL();
3676 if (buffer_type == WINE_GL_BUFFER_FRONT)
3677 /* Application wants to lock the front buffer */
3678 glReadBuffer(GL_FRONT);
3679 else
3680 /* Application wants to lock the back buffer */
3681 glReadBuffer(GL_BACK);
3683 dst = ((char *)This->surface_desc.lpSurface) +
3684 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3686 if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3687 /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3688 * could not be bothered considering the rare cases where it may be useful :-)
3690 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3691 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3692 y--) {
3693 glReadPixels(pRect->left, y,
3694 pRect->right - pRect->left, 1,
3695 buffer_color, buffer_format, dst);
3696 dst += This->surface_desc.u1.lPitch;
3698 } else {
3699 /* Faster path for surface copy. Note that I can use static variables here as I am
3700 * protected by the OpenGL critical section so this function won't be called by
3701 * two threads at the same time.
3703 static char *buffer = NULL;
3704 static int buffer_width = 0;
3705 char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3706 int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3708 glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3709 pRect->right - pRect->left, pRect->bottom - pRect->top,
3710 buffer_color, buffer_format, dst);
3712 if (current_width > buffer_width) {
3713 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3714 buffer_width = current_width;
3715 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3717 for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3718 memcpy(buffer, dst, current_width);
3719 memcpy(dst, dst2, current_width);
3720 memcpy(dst2, buffer, current_width);
3721 dst += This->surface_desc.u1.lPitch;
3722 dst2 -= This->surface_desc.u1.lPitch;
3726 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3728 #if 0
3729 /* I keep this code here as it's very useful to debug :-) */
3731 static int flush_count = 0;
3732 char buf[128];
3733 FILE *f;
3735 if ((++flush_count % 50) == 0) {
3736 sprintf(buf, "lock_%06d.pnm", flush_count);
3737 f = fopen(buf, "wb");
3738 DDRAW_dump_surface_to_disk(This, f);
3741 #endif
3743 LEAVE_GL();
3747 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3748 RECT loc_rect;
3749 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3750 int x, y;
3751 BOOLEAN initial;
3752 DWORD opt_bitmap;
3754 /* Note : no need here to lock the 'device critical section' as we are already protected by
3755 the GL critical section. */
3757 if (pRect == NULL) {
3758 loc_rect.top = 0;
3759 loc_rect.left = 0;
3760 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3761 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3762 pRect = &loc_rect;
3765 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3767 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3769 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3770 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3771 ERR(" unsupported pixel format at frame buffer flush.\n");
3772 return;
3775 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3776 RECT flush_rect;
3778 flush_rect.top = y;
3779 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3781 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3782 /* First, upload the texture... */
3783 flush_rect.left = x;
3784 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3786 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3788 glBegin(GL_QUADS);
3789 glTexCoord2f(0.0, 0.0);
3790 glVertex3d(x, y, 0.5);
3791 glTexCoord2f(1.0, 0.0);
3792 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3793 glTexCoord2f(1.0, 1.0);
3794 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3795 glTexCoord2f(0.0, 1.0);
3796 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3797 glEnd();
3801 upload_surface_to_tex_memory_release();
3802 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3804 #if 0
3805 /* I keep this code here as it's very useful to debug :-) */
3807 static int flush_count = 0;
3808 char buf[128];
3809 FILE *f;
3811 if ((++flush_count % 50) == 0) {
3812 sprintf(buf, "flush_%06d.pnm", flush_count);
3813 f = fopen(buf, "wb");
3814 DDRAW_dump_surface_to_disk(surf, f);
3817 #endif
3820 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3822 WINE_GL_BUFFER_TYPE buffer_type;
3823 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3824 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3826 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3827 buffer_type = WINE_GL_BUFFER_FRONT;
3828 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3829 buffer_type = WINE_GL_BUFFER_BACK;
3830 } else {
3831 ERR("Wrong surface type for locking !\n");
3832 return;
3835 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3836 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3837 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3839 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3841 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3842 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3843 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3844 GLenum prev_draw;
3846 TRACE(" flushing front buffer immediately on screen.\n");
3848 ENTER_GL();
3849 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3850 glDrawBuffer(GL_FRONT);
3851 /* Note: we do not use the application provided lock rectangle but our own stored at
3852 lock time. This is because in old D3D versions, the 'lock' parameter did not
3853 exist.
3855 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]);
3856 glDrawBuffer(prev_draw);
3857 LEAVE_GL();
3858 } else {
3859 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3863 /* And 'frees' the device critical section */
3864 LeaveCriticalSection(&(d3d_dev->crit));
3867 static void
3868 apply_texture_state(IDirect3DDeviceImpl *This)
3870 int stage, state;
3872 /* Initialize texture stages states */
3873 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3874 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3875 if (This->state_block.set_flags.texture_stage_state[stage][state]) {
3876 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3877 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3883 HRESULT
3884 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, int version)
3886 IDirect3DDeviceImpl *object;
3887 IDirect3DDeviceGLImpl *gl_object;
3888 IDirectDrawSurfaceImpl *surf;
3889 HDC device_context;
3890 XVisualInfo *vis;
3891 int num;
3892 int tex_num;
3893 XVisualInfo template;
3894 GLenum buffer = GL_FRONT;
3895 int light;
3897 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
3898 if (object == NULL) return DDERR_OUTOFMEMORY;
3900 gl_object = (IDirect3DDeviceGLImpl *) object;
3902 object->ref = 1;
3903 object->d3d = d3d;
3904 object->surface = surface;
3905 object->set_context = set_context;
3906 object->clear = d3ddevice_clear_back;
3907 object->set_matrices = d3ddevice_set_matrices;
3908 object->matrices_updated = d3ddevice_matrices_updated;
3909 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
3910 object->version = version;
3912 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
3914 InitializeCriticalSection(&(object->crit));
3916 TRACE(" device critical section : %p\n", &(object->crit));
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(" overriding direct surface access.\n");
3980 } else {
3981 TRACE(" no override.\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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3999 object->view_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4000 object->proj_mat = 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] = 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 = 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 InitDefaultStateBlock(&object->state_block, object->version);
4069 /* Apply default render state and texture stage state values */
4070 apply_render_state(object, &object->state_block);
4071 apply_texture_state(object);
4073 /* And fill the fog table with the default fog value */
4074 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4076 return DD_OK;
4079 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4081 pc->dwSize = sizeof(*pc);
4082 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4083 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4084 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4085 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4086 D3DPRASTERCAPS_ZFOG;
4087 if (GL_extensions.mipmap_lodbias) {
4088 pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4090 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4091 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4092 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4093 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4094 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4095 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4096 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4097 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4098 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4099 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4100 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4101 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4102 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4103 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4104 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4105 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4106 D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4107 D3DPTFILTERCAPS_MIPFPOINT;
4108 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4109 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4110 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4111 if (GL_extensions.mirrored_repeat) {
4112 pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4114 pc->dwStippleWidth = 32;
4115 pc->dwStippleHeight = 32;
4118 static void fill_caps(void)
4120 GLint max_clip_planes;
4121 GLint depth_bits;
4123 /* Fill first all the fields with default values which will be overriden later on with
4124 correct ones from the GL code
4126 opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4127 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4128 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4129 /* D3D 7 capabilities */
4130 D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4131 fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4132 fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4133 opengl_device_caps.dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
4134 opengl_device_caps.dwMinTextureWidth = 1;
4135 opengl_device_caps.dwMinTextureHeight = 1;
4136 opengl_device_caps.dwMaxTextureWidth = 1024;
4137 opengl_device_caps.dwMaxTextureHeight = 1024;
4138 opengl_device_caps.dwMaxTextureRepeat = 16;
4139 opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4140 opengl_device_caps.dwMaxAnisotropy = 0;
4141 opengl_device_caps.dvGuardBandLeft = 0.0;
4142 opengl_device_caps.dvGuardBandRight = 0.0;
4143 opengl_device_caps.dvGuardBandTop = 0.0;
4144 opengl_device_caps.dvGuardBandBottom = 0.0;
4145 opengl_device_caps.dvExtentsAdjust = 0.0;
4146 opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4147 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4148 opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4149 D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4150 D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4151 if (GL_extensions.max_texture_units != 0) {
4152 opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4153 opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4154 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4155 } else {
4156 opengl_device_caps.wMaxTextureBlendStages = 1;
4157 opengl_device_caps.wMaxSimultaneousTextures = 1;
4158 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4160 opengl_device_caps.dwMaxActiveLights = 16;
4161 opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4162 opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4163 opengl_device_caps.wMaxUserClipPlanes = 1;
4164 opengl_device_caps.wMaxVertexBlendMatrices = 0;
4165 opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4166 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4167 opengl_device_caps.dwReserved1 = 0;
4168 opengl_device_caps.dwReserved2 = 0;
4169 opengl_device_caps.dwReserved3 = 0;
4170 opengl_device_caps.dwReserved4 = 0;
4172 /* And now some GL overrides :-) */
4173 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4174 opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4175 opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4176 TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4178 glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4179 TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4181 glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4182 opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4183 TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4185 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4186 TRACE(": Z bits = %d\n", depth_bits);
4187 switch (depth_bits) {
4188 case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4189 case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4190 case 32:
4191 default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4195 BOOL
4196 d3ddevice_init_at_startup(void *gl_handle)
4198 XVisualInfo template;
4199 XVisualInfo *vis;
4200 HDC device_context;
4201 Display *display;
4202 Visual *visual;
4203 Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4204 XWindowAttributes win_attr;
4205 GLXContext gl_context;
4206 int num;
4207 const char *glExtensions;
4208 const char *glVersion;
4209 const char *glXExtensions = NULL;
4210 const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4211 int major, minor, patch, num_parsed;
4213 TRACE("Initializing GL...\n");
4215 if (!drawable)
4217 WARN("x11drv not loaded - D3D support disabled!\n");
4218 return FALSE;
4221 /* Get a default rendering context to have the 'caps' function query some info from GL */
4222 device_context = GetDC(0);
4223 display = get_display(device_context);
4224 ReleaseDC(0, device_context);
4226 ENTER_GL();
4227 if (XGetWindowAttributes(display, drawable, &win_attr)) {
4228 visual = win_attr.visual;
4229 } else {
4230 visual = DefaultVisual(display, DefaultScreen(display));
4232 template.visualid = XVisualIDFromVisual(visual);
4233 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4234 if (vis == NULL) {
4235 LEAVE_GL();
4236 WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4237 return FALSE;
4239 gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4241 if (gl_context == NULL) {
4242 LEAVE_GL();
4243 WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4244 return FALSE;
4246 if (glXMakeCurrent(display, drawable, gl_context) == False) {
4247 glXDestroyContext(display, gl_context);
4248 LEAVE_GL();
4249 WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4250 return FALSE;
4253 /* Then, query all extensions */
4254 glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4255 glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4256 glVersion = (const char *) glGetString(GL_VERSION);
4257 if (gl_handle != NULL) {
4258 pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4261 /* Parse the GL version string */
4262 num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4263 if (num_parsed == 1) {
4264 minor = 0;
4265 patch = 0;
4266 } else if (num_parsed == 2) {
4267 patch = 0;
4269 TRACE("GL version %d.%d.%d\n", major, minor, patch);
4271 /* And starts to fill the extension context properly */
4272 memset(&GL_extensions, 0, sizeof(GL_extensions));
4273 TRACE("GL supports following extensions used by Wine :\n");
4275 /* Mirrored Repeat extension :
4276 - GL_ARB_texture_mirrored_repeat
4277 - GL_IBM_texture_mirrored_repeat
4278 - GL >= 1.4
4280 if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4281 (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4282 (major > 1) ||
4283 ((major == 1) && (minor >= 4))) {
4284 TRACE(" - mirrored repeat\n");
4285 GL_extensions.mirrored_repeat = TRUE;
4288 /* Texture LOD Bias :
4289 - GL_EXT_texture_lod_bias
4291 if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4292 TRACE(" - texture lod bias\n");
4293 GL_extensions.mipmap_lodbias = TRUE;
4296 /* For all subsequent extensions, we need glXGetProcAddress */
4297 if (pglXGetProcAddressARB != NULL) {
4298 /* Multi-texturing :
4299 - GL_ARB_multitexture
4300 - GL >= 1.2.1
4302 if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4303 (major > 1) ||
4304 ((major == 1) && (minor > 2)) ||
4305 ((major == 1) && (minor == 2) && (patch >= 1))) {
4306 glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4307 TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4308 /* We query the ARB version to be the most portable we can... */
4309 GL_extensions.glActiveTexture = pglXGetProcAddressARB("glActiveTextureARB");
4310 GL_extensions.glMultiTexCoord2fv = pglXGetProcAddressARB("glMultiTexCoord2fv");
4311 GL_extensions.glClientActiveTexture = pglXGetProcAddressARB("glClientActiveTextureARB");
4314 if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4315 TRACE(" - S3TC compression supported\n");
4316 GL_extensions.s3tc_compressed_texture = TRUE;
4317 GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB("glCompressedTexImage2D");
4318 GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB("glCompressedTexSubImage2D");
4322 /* Fill the D3D capabilities according to what GL tells us... */
4323 fill_caps();
4325 /* And frees this now-useless context */
4326 glXMakeCurrent(display, None, NULL);
4327 glXDestroyContext(display, gl_context);
4328 LEAVE_GL();
4330 return TRUE;