Release 20050930.
[wine/gsoc-2012-control.git] / dlls / ddraw / device_opengl.c
blob33cf9b3f6181cbd487c8c99c65402994d6727504
1 /*
2 * Direct3D Device
4 * Copyright (c) 1998-2004 Lionel Ulmer
5 * Copyright (c) 2002-2005 Christian Costa
7 * This file contains the MESA implementation of all the D3D devices that
8 * Wine supports.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <string.h>
30 #include <math.h>
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
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 static 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 /* Free light arrays */
432 HeapFree(GetProcessHeap(), 0, This->light_parameters);
433 HeapFree(GetProcessHeap(), 0, This->active_lights);
435 HeapFree(GetProcessHeap(), 0, This->world_mat);
436 HeapFree(GetProcessHeap(), 0, This->view_mat);
437 HeapFree(GetProcessHeap(), 0, This->proj_mat);
439 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
441 DeleteCriticalSection(&(This->crit));
443 ENTER_GL();
444 if (glThis->unlock_tex)
445 glDeleteTextures(1, &(glThis->unlock_tex));
446 glXDestroyContext(glThis->display, glThis->gl_context);
447 LEAVE_GL();
448 HeapFree(GetProcessHeap(), 0, This->clipping_planes);
449 HeapFree(GetProcessHeap(), 0, This->vertex_buffer);
451 HeapFree(GetProcessHeap(), 0, This);
452 return 0;
454 return ref;
457 HRESULT WINAPI
458 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
459 LPD3DDEVICEDESC lpD3DHWDevDesc,
460 LPD3DDEVICEDESC lpD3DHELDevDesc)
462 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
463 D3DDEVICEDESC desc;
464 DWORD dwSize;
466 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
468 fill_opengl_caps(&desc);
469 dwSize = lpD3DHWDevDesc->dwSize;
470 memset(lpD3DHWDevDesc, 0, dwSize);
471 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
473 dwSize = lpD3DHELDevDesc->dwSize;
474 memset(lpD3DHELDevDesc, 0, dwSize);
475 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
477 TRACE(" returning caps : (no dump function yet)\n");
479 return DD_OK;
482 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
483 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
484 LPVOID context, int version)
486 DDSURFACEDESC sdesc;
487 LPDDPIXELFORMAT pformat;
489 /* Do the texture enumeration */
490 sdesc.dwSize = sizeof(DDSURFACEDESC);
491 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
492 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
493 pformat = &(sdesc.ddpfPixelFormat);
494 pformat->dwSize = sizeof(DDPIXELFORMAT);
495 pformat->dwFourCC = 0;
497 TRACE("Enumerating GL_RGBA unpacked (32)\n");
498 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
499 pformat->u1.dwRGBBitCount = 32;
500 pformat->u2.dwRBitMask = 0x00FF0000;
501 pformat->u3.dwGBitMask = 0x0000FF00;
502 pformat->u4.dwBBitMask = 0x000000FF;
503 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
504 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
505 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
507 TRACE("Enumerating GL_RGB unpacked (32)\n");
508 pformat->dwFlags = DDPF_RGB;
509 pformat->u1.dwRGBBitCount = 32;
510 pformat->u2.dwRBitMask = 0x00FF0000;
511 pformat->u3.dwGBitMask = 0x0000FF00;
512 pformat->u4.dwBBitMask = 0x000000FF;
513 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
514 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
515 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
517 TRACE("Enumerating GL_RGB unpacked (24)\n");
518 pformat->dwFlags = DDPF_RGB;
519 pformat->u1.dwRGBBitCount = 24;
520 pformat->u2.dwRBitMask = 0x00FF0000;
521 pformat->u3.dwGBitMask = 0x0000FF00;
522 pformat->u4.dwBBitMask = 0x000000FF;
523 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
524 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
525 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
527 /* Note : even if this is an 'emulated' texture format, it needs to be first
528 as some dumb applications seem to rely on that. */
529 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
530 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
531 pformat->u1.dwRGBBitCount = 16;
532 pformat->u2.dwRBitMask = 0x00007C00;
533 pformat->u3.dwGBitMask = 0x000003E0;
534 pformat->u4.dwBBitMask = 0x0000001F;
535 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
536 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
537 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
539 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
540 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
541 pformat->u1.dwRGBBitCount = 16;
542 pformat->u2.dwRBitMask = 0x00000F00;
543 pformat->u3.dwGBitMask = 0x000000F0;
544 pformat->u4.dwBBitMask = 0x0000000F;
545 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
546 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
547 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
549 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
550 pformat->dwFlags = DDPF_RGB;
551 pformat->u1.dwRGBBitCount = 16;
552 pformat->u2.dwRBitMask = 0x0000F800;
553 pformat->u3.dwGBitMask = 0x000007E0;
554 pformat->u4.dwBBitMask = 0x0000001F;
555 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
556 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
557 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
559 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
560 pformat->dwFlags = DDPF_RGB;
561 pformat->u1.dwRGBBitCount = 16;
562 pformat->u2.dwRBitMask = 0x00007C00;
563 pformat->u3.dwGBitMask = 0x000003E0;
564 pformat->u4.dwBBitMask = 0x0000001F;
565 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
566 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
567 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
569 #if 0
570 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
571 find enumerated, others the last one. And both want to have the ARGB one.
573 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
575 /* See argument about the RGBA format for 'packed' texture formats */
576 TRACE("Enumerating GL_RGBA unpacked (32)\n");
577 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
578 pformat->u1.dwRGBBitCount = 32;
579 pformat->u2.dwRBitMask = 0xFF000000;
580 pformat->u3.dwGBitMask = 0x00FF0000;
581 pformat->u4.dwBBitMask = 0x0000FF00;
582 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
583 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
584 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
586 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
587 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
588 pformat->u1.dwRGBBitCount = 16;
589 pformat->u2.dwRBitMask = 0x0000F000;
590 pformat->u3.dwGBitMask = 0x00000F00;
591 pformat->u4.dwBBitMask = 0x000000F0;
592 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
593 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
594 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
596 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
597 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
598 pformat->u1.dwRGBBitCount = 16;
599 pformat->u2.dwRBitMask = 0x0000F800;
600 pformat->u3.dwGBitMask = 0x000007C0;
601 pformat->u4.dwBBitMask = 0x0000003E;
602 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
603 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
604 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
605 #endif
607 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
608 pformat->dwFlags = DDPF_RGB;
609 pformat->u1.dwRGBBitCount = 8;
610 pformat->u2.dwRBitMask = 0x000000E0;
611 pformat->u3.dwGBitMask = 0x0000001C;
612 pformat->u4.dwBBitMask = 0x00000003;
613 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
614 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
615 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
617 TRACE("Enumerating Paletted (8)\n");
618 pformat->dwFlags = DDPF_PALETTEINDEXED8;
619 pformat->u1.dwRGBBitCount = 8;
620 pformat->u2.dwRBitMask = 0x00000000;
621 pformat->u3.dwGBitMask = 0x00000000;
622 pformat->u4.dwBBitMask = 0x00000000;
623 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
624 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
625 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
627 /* DXT textures only exist for devices created from IDirect3D3 and above */
628 if ((version >= 3) && GL_extensions.s3tc_compressed_texture) {
629 TRACE("Enumerating DXT1\n");
630 pformat->dwFlags = DDPF_FOURCC;
631 pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
632 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
633 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
635 TRACE("Enumerating DXT3\n");
636 pformat->dwFlags = DDPF_FOURCC;
637 pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
638 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
639 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
641 TRACE("Enumerating DXT5\n");
642 pformat->dwFlags = DDPF_FOURCC;
643 pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
644 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
645 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
648 TRACE("End of enumeration\n");
649 return DD_OK;
653 HRESULT
654 d3ddevice_find(IDirectDrawImpl *d3d,
655 LPD3DFINDDEVICESEARCH lpD3DDFS,
656 LPD3DFINDDEVICERESULT lplpD3DDevice)
658 D3DDEVICEDESC desc;
660 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
661 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
662 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
663 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
665 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
666 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
667 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
668 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
669 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
670 TRACE(" no match for this GUID.\n");
671 return DDERR_INVALIDPARAMS;
675 /* Now return our own GUID */
676 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
677 fill_opengl_caps(&desc);
678 lplpD3DDevice->ddHwDesc = desc;
679 lplpD3DDevice->ddSwDesc = desc;
681 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
683 return D3D_OK;
686 HRESULT WINAPI
687 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
688 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
689 LPVOID lpArg)
691 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
692 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
693 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg, This->version);
696 static HRESULT WINAPI
697 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
698 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
699 LPVOID lpArg)
701 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
702 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
703 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg, This->version);
706 static HRESULT WINAPI
707 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
708 D3DRENDERSTATETYPE dwRenderStateType,
709 DWORD dwRenderState)
711 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
712 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
714 /* Call the render state functions */
715 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
716 set_render_state(This, dwRenderStateType, &This->state_block);
718 return DD_OK;
721 static HRESULT WINAPI
722 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
723 D3DRENDERSTATETYPE dwRenderStateType,
724 LPDWORD lpdwRenderState)
726 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
727 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
729 /* Call the render state functions */
730 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
732 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
734 return DD_OK;
737 static HRESULT WINAPI
738 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
739 D3DLIGHTSTATETYPE dwLightStateType,
740 LPDWORD lpdwLightState)
742 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
744 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
746 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
747 TRACE("Unexpected Light State Type\n");
748 return DDERR_INVALIDPARAMS;
751 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
752 *lpdwLightState = This->material;
753 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
754 *lpdwLightState = D3DCOLOR_RGB;
755 } else {
756 D3DRENDERSTATETYPE rs;
757 switch (dwLightStateType) {
758 case D3DLIGHTSTATE_AMBIENT: /* 2 */
759 rs = D3DRENDERSTATE_AMBIENT;
760 break;
761 case D3DLIGHTSTATE_FOGMODE: /* 4 */
762 rs = D3DRENDERSTATE_FOGVERTEXMODE;
763 break;
764 case D3DLIGHTSTATE_FOGSTART: /* 5 */
765 rs = D3DRENDERSTATE_FOGSTART;
766 break;
767 case D3DLIGHTSTATE_FOGEND: /* 6 */
768 rs = D3DRENDERSTATE_FOGEND;
769 break;
770 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
771 rs = D3DRENDERSTATE_FOGDENSITY;
772 break;
773 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
774 rs = D3DRENDERSTATE_COLORVERTEX;
775 break;
776 default:
777 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
778 return DDERR_INVALIDPARAMS;
781 IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
782 rs,lpdwLightState);
785 return DD_OK;
788 static HRESULT WINAPI
789 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
790 D3DLIGHTSTATETYPE dwLightStateType,
791 DWORD dwLightState)
793 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
795 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
797 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
798 TRACE("Unexpected Light State Type\n");
799 return DDERR_INVALIDPARAMS;
802 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
803 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
805 if (mat != NULL) {
806 TRACE(" activating material %p.\n", mat);
807 mat->activate(mat);
808 } else {
809 FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
811 This->material = dwLightState;
812 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
813 switch (dwLightState) {
814 case D3DCOLOR_MONO:
815 ERR("DDCOLOR_MONO should not happen!\n");
816 break;
817 case D3DCOLOR_RGB:
818 /* We are already in this mode */
819 TRACE("Setting color model to RGB (no-op).\n");
820 break;
821 default:
822 ERR("Unknown color model!\n");
823 return DDERR_INVALIDPARAMS;
825 } else {
826 D3DRENDERSTATETYPE rs;
827 switch (dwLightStateType) {
828 case D3DLIGHTSTATE_AMBIENT: /* 2 */
829 rs = D3DRENDERSTATE_AMBIENT;
830 break;
831 case D3DLIGHTSTATE_FOGMODE: /* 4 */
832 rs = D3DRENDERSTATE_FOGVERTEXMODE;
833 break;
834 case D3DLIGHTSTATE_FOGSTART: /* 5 */
835 rs = D3DRENDERSTATE_FOGSTART;
836 break;
837 case D3DLIGHTSTATE_FOGEND: /* 6 */
838 rs = D3DRENDERSTATE_FOGEND;
839 break;
840 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
841 rs = D3DRENDERSTATE_FOGDENSITY;
842 break;
843 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
844 rs = D3DRENDERSTATE_COLORVERTEX;
845 break;
846 default:
847 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
848 return DDERR_INVALIDPARAMS;
851 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
852 rs,dwLightState);
855 return DD_OK;
858 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
860 switch (d3dpt) {
861 case D3DPT_POINTLIST:
862 TRACE(" primitive type is POINTS\n");
863 return GL_POINTS;
865 case D3DPT_LINELIST:
866 TRACE(" primitive type is LINES\n");
867 return GL_LINES;
869 case D3DPT_LINESTRIP:
870 TRACE(" primitive type is LINE_STRIP\n");
871 return GL_LINE_STRIP;
873 case D3DPT_TRIANGLELIST:
874 TRACE(" primitive type is TRIANGLES\n");
875 return GL_TRIANGLES;
877 case D3DPT_TRIANGLESTRIP:
878 TRACE(" primitive type is TRIANGLE_STRIP\n");
879 return GL_TRIANGLE_STRIP;
881 case D3DPT_TRIANGLEFAN:
882 TRACE(" primitive type is TRIANGLE_FAN\n");
883 return GL_TRIANGLE_FAN;
885 default:
886 FIXME("Unhandled primitive %08x\n", d3dpt);
887 return GL_POINTS;
891 /* This function calculate the Z coordinate from Zproj */
892 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
894 float a,b,c,d;
895 /* Assume that X = Y = 0 and W = 1 */
896 a = This->proj_mat->_33;
897 b = This->proj_mat->_34;
898 c = This->proj_mat->_43;
899 d = This->proj_mat->_44;
900 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
901 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
902 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
904 return (d*Zproj - c) / (a - b*Zproj);
907 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
908 int i;
910 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
912 for (i = 0; i < 3; i++) {
913 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
914 DWORD elt;
915 for (elt = 0; elt < 0x10000; elt++) {
916 /* We apply the fog transformation and cache the result */
917 DWORD fog_intensity = elt & 0xFF;
918 DWORD vertex_color = (elt >> 8) & 0xFF;
919 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
924 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
925 BOOLEAN vertex_transformed,
926 BOOLEAN vertex_lit) {
927 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
929 /* Puts GL in the correct lighting / transformation mode */
930 if ((vertex_transformed == FALSE) &&
931 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
932 /* Need to put the correct transformation again if we go from Transformed
933 vertices to non-transformed ones.
935 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
936 This->world_mat, This->view_mat, This->proj_mat);
937 glThis->transform_state = GL_TRANSFORM_NORMAL;
939 } else if (vertex_transformed &&
940 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
941 /* Set our orthographic projection */
942 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
943 glThis->transform_state = GL_TRANSFORM_ORTHO;
944 d3ddevice_set_ortho(This);
948 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
949 if no fogging state change occurred */
950 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
951 if (vertex_transformed) {
952 if (glThis->fogging != 0) {
953 glDisable(GL_FOG);
954 glThis->fogging = 0;
956 /* Now check if our fog_table still corresponds to the current vertex color.
957 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
958 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
959 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
960 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
961 /* We need to rebuild our fog table.... */
962 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
964 } else {
965 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
966 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
967 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
968 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
969 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
971 if (vertex_lit == FALSE) {
972 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
973 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
974 } else {
975 /* Special case of 'pixel fog' */
976 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
977 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
979 if (glThis->fogging == 0) {
980 glEnable(GL_FOG);
981 glThis->fogging = 1;
983 } else {
984 if (glThis->fogging != 0) {
985 glDisable(GL_FOG);
986 glThis->fogging = 0;
990 } else {
991 if (glThis->fogging != 0) {
992 glDisable(GL_FOG);
993 glThis->fogging = 0;
997 /* Handle the 'no-normal' case */
998 if ((vertex_lit == FALSE) && This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1]) {
999 if (glThis->lighting == 0) {
1000 glEnable(GL_LIGHTING);
1001 glThis->lighting = 1;
1003 } else {
1004 if (glThis->lighting != 0) {
1005 glDisable(GL_LIGHTING);
1006 glThis->lighting = 0;
1010 /* Handle the code for pre-vertex material properties */
1011 if (vertex_transformed == FALSE) {
1012 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1013 This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1014 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1015 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1016 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1017 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1018 glEnable(GL_COLOR_MATERIAL);
1025 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1026 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1028 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1030 switch (d3dvt) {
1031 case D3DVT_VERTEX: {
1032 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1033 strided.position.dwStride = sizeof(D3DVERTEX);
1034 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1035 strided.normal.dwStride = sizeof(D3DVERTEX);
1036 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1037 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1038 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1039 } break;
1041 case D3DVT_LVERTEX: {
1042 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1043 strided.position.dwStride = sizeof(D3DLVERTEX);
1044 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1045 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1046 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1047 strided.specular.dwStride = sizeof(D3DLVERTEX);
1048 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1049 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1050 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1051 } break;
1053 case D3DVT_TLVERTEX: {
1054 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1055 strided.position.dwStride = sizeof(D3DTLVERTEX);
1056 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1057 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1058 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1059 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1060 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1061 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1062 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1063 } break;
1065 default:
1066 FIXME("Unhandled vertex type %08x\n", d3dvt);
1067 break;
1071 HRESULT WINAPI
1072 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1073 D3DPRIMITIVETYPE d3dptPrimitiveType,
1074 D3DVERTEXTYPE d3dvtVertexType,
1075 LPVOID lpvVertices,
1076 DWORD dwVertexCount,
1077 DWORD dwFlags)
1079 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1081 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1082 if (TRACE_ON(ddraw)) {
1083 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1086 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1088 return DD_OK;
1091 HRESULT WINAPI
1092 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1093 D3DPRIMITIVETYPE d3dptPrimitiveType,
1094 D3DVERTEXTYPE d3dvtVertexType,
1095 LPVOID lpvVertices,
1096 DWORD dwVertexCount,
1097 LPWORD dwIndices,
1098 DWORD dwIndexCount,
1099 DWORD dwFlags)
1101 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1102 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1103 if (TRACE_ON(ddraw)) {
1104 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1107 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1109 return DD_OK;
1112 HRESULT WINAPI
1113 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1114 LPD3DEXECUTEBUFFERDESC lpDesc,
1115 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1116 IUnknown* pUnkOuter)
1118 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1119 IDirect3DExecuteBufferImpl *ret;
1120 HRESULT ret_value;
1122 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1124 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1125 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1127 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1129 return ret_value;
1132 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1133 static BOOLEAN first = TRUE;
1134 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1135 unsigned int row;
1136 GLenum type;
1138 if (first) {
1139 MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1140 first = FALSE;
1143 TRACE("flushing ZBuffer back to GL\n");
1145 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1146 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1147 d3ddevice_set_ortho(d3d_dev);
1150 glMatrixMode(GL_MODELVIEW);
1151 glLoadIdentity();
1153 if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1154 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1155 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1157 /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1158 in some drivers...
1160 switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1161 case 16: type = GL_UNSIGNED_SHORT; break;
1162 case 32: type = GL_UNSIGNED_INT; break;
1163 default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1166 for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1167 /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1168 glRasterPos2i(0, row + 1);
1169 glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1170 ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1173 restore_state:
1174 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1175 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1176 glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1177 if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1180 /* These are the various handler used in the generic path */
1181 inline static void handle_xyz(D3DVALUE *coords) {
1182 glVertex3fv(coords);
1184 inline static void handle_xyzrhw(D3DVALUE *coords) {
1185 if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1186 glVertex3fv(coords);
1187 else {
1188 GLfloat w = 1.0 / coords[3];
1190 glVertex4f(coords[0] * w,
1191 coords[1] * w,
1192 coords[2] * w,
1196 inline static void handle_normal(D3DVALUE *coords) {
1197 glNormal3fv(coords);
1200 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1201 if (sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] ||
1202 sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1]) {
1203 glColor4ub((*color >> 16) & 0xFF,
1204 (*color >> 8) & 0xFF,
1205 (*color >> 0) & 0xFF,
1206 (*color >> 24) & 0xFF);
1207 } else {
1208 glColor3ub((*color >> 16) & 0xFF,
1209 (*color >> 8) & 0xFF,
1210 (*color >> 0) & 0xFF);
1214 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1215 glColor4ub((*color >> 16) & 0xFF,
1216 (*color >> 8) & 0xFF,
1217 (*color >> 0) & 0xFF,
1218 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1221 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1222 if ((lighted == FALSE) &&
1223 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1224 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1225 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1226 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1227 handle_diffuse_base(sb, color);
1229 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1230 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1231 handle_diffuse_base(sb, color);
1233 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1234 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1235 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1236 handle_diffuse_base(sb, color);
1238 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1239 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1240 handle_diffuse_base(sb, color);
1242 } else {
1243 handle_diffuse_base(sb, color);
1247 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1248 if ((lighted == FALSE) &&
1249 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1250 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1251 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1252 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1253 handle_specular_base(sb, color);
1255 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1256 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1257 handle_specular_base(sb, color);
1259 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1260 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1261 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1262 handle_specular_base(sb, color);
1264 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1265 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1266 handle_specular_base(sb, color);
1269 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1272 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1273 if (lighted) {
1274 DWORD color = *color_d;
1275 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
1276 /* Special case where the specular value is used to do fogging */
1277 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1278 color &= 0xFF000000; /* Only keep the alpha component */
1279 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1280 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1281 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1283 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1284 /* Standard specular value in transformed mode. TODO */
1286 handle_diffuse_base(sb, &color);
1287 } else {
1288 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1289 handle_diffuse(sb, color_d, FALSE);
1290 handle_specular(sb, color_s, FALSE);
1291 } else {
1292 /* In that case, only put the diffuse color... */
1293 handle_diffuse_base(sb, color_d);
1298 static void handle_texture(DWORD size, const D3DVALUE *coords) {
1299 switch (size) {
1300 case 1: glTexCoord1fv(coords); break;
1301 case 2: glTexCoord2fv(coords); break;
1302 case 3: glTexCoord3fv(coords); break;
1303 case 4: glTexCoord4fv(coords); break;
1307 inline static void handle_textures(DWORD size, const D3DVALUE *coords, int tex_stage) {
1308 if (GL_extensions.max_texture_units > 0) {
1309 GL_extensions.glMultiTexCoord[size - 1](GL_TEXTURE0_WINE + tex_stage, coords);
1310 } else {
1311 if (tex_stage == 0) handle_texture(size, coords);
1315 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1316 D3DPRIMITIVETYPE d3dptPrimitiveType,
1317 DWORD d3dvtVertexType,
1318 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1319 DWORD dwVertexCount,
1320 LPWORD dwIndices,
1321 DWORD dwIndexCount,
1322 DWORD dwFlags)
1324 BOOLEAN vertex_lighted = FALSE;
1325 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1326 int num_active_stages = 0;
1327 int num_tex_index = GET_TEXCOUNT_FROM_FVF(d3dvtVertexType);
1329 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1330 if (TRACE_ON(ddraw)) {
1331 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1334 /* This is to prevent 'thread contention' between a thread locking the device and another
1335 doing 3D display on it... */
1336 EnterCriticalSection(&(This->crit));
1338 ENTER_GL();
1339 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1340 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1342 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1344 if (This->current_zbuffer == NULL) {
1345 /* Search for an attached ZBuffer */
1346 static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1347 LPDIRECTDRAWSURFACE7 zbuf;
1348 HRESULT hr;
1350 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1351 (DDSCAPS2 *) &zbuf_caps, &zbuf);
1352 if (!FAILED(hr)) {
1353 This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1354 IDirectDrawSurface7_Release(zbuf);
1357 if (This->current_zbuffer != NULL) {
1358 if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1359 flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1363 if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1364 ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1365 vertex_lighted = TRUE;
1367 /* Compute the number of active texture stages and set the various texture parameters */
1368 num_active_stages = draw_primitive_handle_textures(This);
1370 /* And restore to handle '0' in the case we use glTexCoord calls */
1371 if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1372 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1373 glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1376 draw_primitive_handle_GL_state(This,
1377 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1378 vertex_lighted);
1380 /* First, see if we can use the OpenGL vertex arrays... This is very limited
1381 for now to some 'special' cases where we can do a direct mapping between D3D
1382 types and GL types.
1384 Note: in the future all calls will go through vertex arrays but the arrays
1385 will be generated by this function.
1387 Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1388 (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1389 which, as we are little indian, gives a B, G, R, A storage in memory.
1391 if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1392 ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1393 int tex_stage;
1394 TRACE(" using GL vertex arrays for performance !\n");
1395 /* First, the vertices (we are sure we have some :-) */
1396 glEnableClientState(GL_VERTEX_ARRAY);
1397 glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1398 /* Then the normals */
1399 if (d3dvtVertexType & D3DFVF_NORMAL) {
1400 glEnableClientState(GL_NORMAL_ARRAY);
1401 glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1403 /* Then the diffuse colour */
1404 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1405 glEnableClientState(GL_COLOR_ARRAY);
1406 glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1407 ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1409 /* Then the various textures */
1410 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1411 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1412 if (tex_index >= num_tex_index) {
1413 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1414 tex_index = num_tex_index - 1;
1416 if (GL_extensions.glClientActiveTexture) {
1417 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1419 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1420 glTexCoordPointer(GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index), GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1421 lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1423 if (dwIndices != NULL) {
1424 glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1425 } else {
1426 glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1428 glDisableClientState(GL_VERTEX_ARRAY);
1429 if (d3dvtVertexType & D3DFVF_NORMAL) {
1430 glDisableClientState(GL_NORMAL_ARRAY);
1432 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1433 glDisableClientState(GL_COLOR_ARRAY);
1435 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1436 if (GL_extensions.glClientActiveTexture) {
1437 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1439 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1441 } else {
1442 glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1444 /* Some fast paths first before the generic case.... */
1445 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1446 unsigned int index;
1448 for (index = 0; index < dwIndexCount; index++) {
1449 int i = (dwIndices == NULL) ? index : dwIndices[index];
1450 D3DVALUE *normal =
1451 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1452 D3DVALUE *tex_coord =
1453 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1454 D3DVALUE *position =
1455 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1457 handle_normal(normal);
1458 handle_texture(2, tex_coord);
1459 handle_xyz(position);
1461 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1462 position[0], position[1], position[2],
1463 normal[0], normal[1], normal[2],
1464 tex_coord[0], tex_coord[1]);
1466 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1467 unsigned int index;
1469 for (index = 0; index < dwIndexCount; index++) {
1470 int i = (dwIndices == NULL) ? index : dwIndices[index];
1471 DWORD *color_d =
1472 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1473 DWORD *color_s =
1474 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1475 D3DVALUE *tex_coord =
1476 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1477 D3DVALUE *position =
1478 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1480 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1481 handle_texture(2, tex_coord);
1482 handle_xyzrhw(position);
1484 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1485 position[0], position[1], position[2], position[3],
1486 (*color_d >> 16) & 0xFF,
1487 (*color_d >> 8) & 0xFF,
1488 (*color_d >> 0) & 0xFF,
1489 (*color_d >> 24) & 0xFF,
1490 (*color_s >> 16) & 0xFF,
1491 (*color_s >> 8) & 0xFF,
1492 (*color_s >> 0) & 0xFF,
1493 (*color_s >> 24) & 0xFF,
1494 tex_coord[0], tex_coord[1]);
1496 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1497 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1498 /* This is the 'slow path' but that should support all possible vertex formats out there...
1499 Note that people should write a fast path for all vertex formats out there...
1501 unsigned int index;
1502 /* static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 }; */
1504 for (index = 0; index < dwIndexCount; index++) {
1505 int i = (dwIndices == NULL) ? index : dwIndices[index];
1506 int tex_stage;
1508 if (d3dvtVertexType & D3DFVF_NORMAL) {
1509 D3DVALUE *normal =
1510 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1511 handle_normal(normal);
1513 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1514 DWORD *color_d =
1515 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1516 DWORD *color_s =
1517 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1518 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1519 } else {
1520 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1521 DWORD *color_s =
1522 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1523 handle_specular(&(This->state_block), color_s, vertex_lighted);
1524 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1525 DWORD *color_d =
1526 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1527 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1531 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1532 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1533 D3DVALUE *tex_coord;
1535 if (tex_index >= num_tex_index) {
1536 /* This will have to be checked on Windows. RealMYST uses this feature and I would find it more
1537 * logical to re-use the index of the previous stage than a default index of '0'.
1540 /* handle_textures((const D3DVALUE *) no_index, tex_stage); */
1541 tex_index = num_tex_index - 1;
1543 tex_coord = (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1544 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1545 handle_textures(GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index), tex_coord, tex_stage);
1548 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1549 D3DVALUE *position =
1550 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1551 handle_xyz(position);
1552 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1553 D3DVALUE *position =
1554 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1555 handle_xyzrhw(position);
1558 if (TRACE_ON(ddraw_geom)) {
1559 unsigned int tex_index;
1561 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1562 D3DVALUE *position =
1563 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1564 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1565 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1566 D3DVALUE *position =
1567 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1568 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1570 if (d3dvtVertexType & D3DFVF_NORMAL) {
1571 D3DVALUE *normal =
1572 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1573 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1575 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1576 DWORD *color_d =
1577 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1578 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1579 (*color_d >> 16) & 0xFF,
1580 (*color_d >> 8) & 0xFF,
1581 (*color_d >> 0) & 0xFF,
1582 (*color_d >> 24) & 0xFF);
1584 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1585 DWORD *color_s =
1586 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1587 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1588 (*color_s >> 16) & 0xFF,
1589 (*color_s >> 8) & 0xFF,
1590 (*color_s >> 0) & 0xFF,
1591 (*color_s >> 24) & 0xFF);
1593 for (tex_index = 0; tex_index < GET_TEXCOUNT_FROM_FVF(d3dvtVertexType); tex_index++) {
1594 D3DVALUE *tex_coord =
1595 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1596 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1597 switch (GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index)) {
1598 case 1: TRACE_(ddraw_geom)(" / %f", tex_coord[0]); break;
1599 case 2: TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]); break;
1600 case 3: TRACE_(ddraw_geom)(" / %f %f %f", tex_coord[0], tex_coord[1], tex_coord[2]); break;
1601 case 4: TRACE_(ddraw_geom)(" / %f %f %f %f", tex_coord[0], tex_coord[1], tex_coord[2], tex_coord[3]); break;
1602 default: TRACE_(ddraw_geom)("Invalid texture size (%ld) !!!", GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index)); break;
1605 TRACE_(ddraw_geom)("\n");
1608 } else {
1609 ERR(" matrix weighting not handled yet....\n");
1612 glEnd();
1615 /* Whatever the case, disable the color material stuff */
1616 glDisable(GL_COLOR_MATERIAL);
1618 LEAVE_GL();
1619 TRACE("End\n");
1621 LeaveCriticalSection(&(This->crit));
1624 HRESULT WINAPI
1625 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1626 D3DPRIMITIVETYPE d3dptPrimitiveType,
1627 DWORD d3dvtVertexType,
1628 LPVOID lpvVertices,
1629 DWORD dwVertexCount,
1630 DWORD dwFlags)
1632 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1633 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1635 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1636 if (TRACE_ON(ddraw)) {
1637 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1640 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1641 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1643 return DD_OK;
1646 HRESULT WINAPI
1647 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1648 D3DPRIMITIVETYPE d3dptPrimitiveType,
1649 DWORD d3dvtVertexType,
1650 LPVOID lpvVertices,
1651 DWORD dwVertexCount,
1652 LPWORD dwIndices,
1653 DWORD dwIndexCount,
1654 DWORD dwFlags)
1656 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1657 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1659 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1660 if (TRACE_ON(ddraw)) {
1661 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1664 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1665 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1667 return DD_OK;
1670 HRESULT WINAPI
1671 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1672 D3DPRIMITIVETYPE d3dptPrimitiveType,
1673 DWORD dwVertexType,
1674 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1675 DWORD dwVertexCount,
1676 DWORD dwFlags)
1678 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1680 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1681 if (TRACE_ON(ddraw)) {
1682 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1684 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1686 return DD_OK;
1689 HRESULT WINAPI
1690 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1691 D3DPRIMITIVETYPE d3dptPrimitiveType,
1692 DWORD dwVertexType,
1693 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1694 DWORD dwVertexCount,
1695 LPWORD lpIndex,
1696 DWORD dwIndexCount,
1697 DWORD dwFlags)
1699 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1701 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1702 if (TRACE_ON(ddraw)) {
1703 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1706 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1708 return DD_OK;
1711 HRESULT WINAPI
1712 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1713 D3DPRIMITIVETYPE d3dptPrimitiveType,
1714 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1715 DWORD dwStartVertex,
1716 DWORD dwNumVertices,
1717 DWORD dwFlags)
1719 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1720 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1721 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1723 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1724 if (TRACE_ON(ddraw)) {
1725 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1728 if (vb_impl->processed) {
1729 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1730 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1732 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1733 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1734 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1736 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1737 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1739 } else {
1740 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1741 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1744 return DD_OK;
1747 HRESULT WINAPI
1748 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1749 D3DPRIMITIVETYPE d3dptPrimitiveType,
1750 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1751 DWORD dwStartVertex,
1752 DWORD dwNumVertices,
1753 LPWORD lpwIndices,
1754 DWORD dwIndexCount,
1755 DWORD dwFlags)
1757 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1758 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1759 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1761 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1762 if (TRACE_ON(ddraw)) {
1763 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1766 if (vb_impl->processed) {
1767 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1768 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1770 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1771 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1772 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1774 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1775 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1777 } else {
1778 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1779 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1782 return DD_OK;
1785 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1786 static BOOLEAN
1787 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1789 BOOLEAN is_complement = FALSE;
1790 BOOLEAN is_alpha_replicate = FALSE;
1791 BOOLEAN handled = TRUE;
1792 GLenum src;
1793 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1794 int num;
1796 if (is_color) {
1797 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1798 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1799 else {
1800 handled = FALSE;
1801 num = 0;
1803 if (tex_op == D3DTOP_SELECTARG2) {
1804 num = 1 - num;
1806 } else {
1807 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1808 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1809 else {
1810 handled = FALSE;
1811 num = 0;
1813 if (tex_op == D3DTOP_SELECTARG2) {
1814 num = 1 - num;
1818 if (dwState & D3DTA_COMPLEMENT) {
1819 is_complement = TRUE;
1821 if (dwState & D3DTA_ALPHAREPLICATE) {
1822 is_alpha_replicate = TRUE;
1824 dwState &= D3DTA_SELECTMASK;
1825 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1826 dwState = D3DTA_DIFFUSE;
1829 switch (dwState) {
1830 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1831 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1832 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1833 case D3DTA_TFACTOR: {
1834 /* Get the constant value from the current rendering state */
1835 GLfloat color[4];
1836 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1838 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1839 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1840 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1841 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1842 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1844 src = GL_CONSTANT_EXT;
1845 } break;
1846 default: src = GL_TEXTURE; handled = FALSE; break;
1849 if (is_color) {
1850 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1851 if (is_alpha_replicate) {
1852 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1853 } else {
1854 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1856 } else {
1857 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1858 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1861 return handled;
1864 HRESULT WINAPI
1865 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1866 DWORD dwStage,
1867 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1868 DWORD dwState)
1870 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1871 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1872 const char *type;
1873 DWORD prev_state;
1874 GLenum unit;
1876 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1878 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1879 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1880 return DD_OK;
1883 unit = GL_TEXTURE0_WINE + dwStage;
1884 if (unit != glThis->current_active_tex_unit) {
1885 GL_extensions.glActiveTexture(unit);
1886 glThis->current_active_tex_unit = unit;
1889 switch (d3dTexStageStateType) {
1890 #define GEN_CASE(a) case a: type = #a; break
1891 GEN_CASE(D3DTSS_COLOROP);
1892 GEN_CASE(D3DTSS_COLORARG1);
1893 GEN_CASE(D3DTSS_COLORARG2);
1894 GEN_CASE(D3DTSS_ALPHAOP);
1895 GEN_CASE(D3DTSS_ALPHAARG1);
1896 GEN_CASE(D3DTSS_ALPHAARG2);
1897 GEN_CASE(D3DTSS_BUMPENVMAT00);
1898 GEN_CASE(D3DTSS_BUMPENVMAT01);
1899 GEN_CASE(D3DTSS_BUMPENVMAT10);
1900 GEN_CASE(D3DTSS_BUMPENVMAT11);
1901 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1902 GEN_CASE(D3DTSS_ADDRESS);
1903 GEN_CASE(D3DTSS_ADDRESSU);
1904 GEN_CASE(D3DTSS_ADDRESSV);
1905 GEN_CASE(D3DTSS_BORDERCOLOR);
1906 GEN_CASE(D3DTSS_MAGFILTER);
1907 GEN_CASE(D3DTSS_MINFILTER);
1908 GEN_CASE(D3DTSS_MIPFILTER);
1909 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1910 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1911 GEN_CASE(D3DTSS_MAXANISOTROPY);
1912 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1913 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1914 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1915 #undef GEN_CASE
1916 default: type = "UNKNOWN";
1919 /* Store the values in the state array */
1920 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1921 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1922 /* Some special cases when one state modifies more than one... */
1923 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1924 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1925 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1928 ENTER_GL();
1930 switch (d3dTexStageStateType) {
1931 case D3DTSS_MINFILTER:
1932 case D3DTSS_MIPFILTER:
1933 if (TRACE_ON(ddraw)) {
1934 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1935 switch ((D3DTEXTUREMINFILTER) dwState) {
1936 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1937 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1938 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1940 } else {
1941 switch ((D3DTEXTUREMIPFILTER) dwState) {
1942 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1943 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1944 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1945 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1949 break;
1951 case D3DTSS_MAGFILTER:
1952 if (TRACE_ON(ddraw)) {
1953 switch ((D3DTEXTUREMAGFILTER) dwState) {
1954 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1955 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1956 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1959 break;
1961 case D3DTSS_ADDRESS:
1962 case D3DTSS_ADDRESSU:
1963 case D3DTSS_ADDRESSV: {
1964 switch ((D3DTEXTUREADDRESS) dwState) {
1965 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1966 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1967 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1968 case D3DTADDRESS_MIRROR:
1969 if (GL_extensions.mirrored_repeat) {
1970 TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1971 } else {
1972 FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1974 break;
1975 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1977 } break;
1979 case D3DTSS_ALPHAOP:
1980 case D3DTSS_COLOROP: {
1981 int scale = 1;
1982 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1983 const char *value;
1984 int handled = 1;
1986 switch (dwState) {
1987 #define GEN_CASE(a) case a: value = #a; break
1988 GEN_CASE(D3DTOP_DISABLE);
1989 GEN_CASE(D3DTOP_SELECTARG1);
1990 GEN_CASE(D3DTOP_SELECTARG2);
1991 GEN_CASE(D3DTOP_MODULATE);
1992 GEN_CASE(D3DTOP_MODULATE2X);
1993 GEN_CASE(D3DTOP_MODULATE4X);
1994 GEN_CASE(D3DTOP_ADD);
1995 GEN_CASE(D3DTOP_ADDSIGNED);
1996 GEN_CASE(D3DTOP_ADDSIGNED2X);
1997 GEN_CASE(D3DTOP_SUBTRACT);
1998 GEN_CASE(D3DTOP_ADDSMOOTH);
1999 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
2000 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
2001 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
2002 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
2003 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
2004 GEN_CASE(D3DTOP_PREMODULATE);
2005 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
2006 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
2007 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
2008 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
2009 GEN_CASE(D3DTOP_BUMPENVMAP);
2010 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
2011 GEN_CASE(D3DTOP_DOTPRODUCT3);
2012 GEN_CASE(D3DTOP_FORCE_DWORD);
2013 #undef GEN_CASE
2014 default: value = "UNKNOWN";
2017 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
2018 glDisable(GL_TEXTURE_2D);
2019 TRACE(" disabling 2D texturing.\n");
2020 } else {
2021 /* Re-enable texturing only if COLOROP was not already disabled... */
2022 if ((glThis->current_bound_texture[dwStage] != NULL) &&
2023 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2024 glEnable(GL_TEXTURE_2D);
2025 TRACE(" enabling 2D texturing.\n");
2028 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2029 if ((dwState != D3DTOP_DISABLE) &&
2030 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2031 if (glThis->current_tex_env != GL_COMBINE_EXT) {
2032 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2033 glThis->current_tex_env = GL_COMBINE_EXT;
2037 /* Now set up the operand correctly */
2038 switch (dwState) {
2039 case D3DTOP_DISABLE:
2040 /* Contrary to the docs, alpha can be disabled when colorop is enabled
2041 and it works, so ignore this op */
2042 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2043 break;
2045 case D3DTOP_SELECTARG1:
2046 case D3DTOP_SELECTARG2:
2047 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2048 break;
2050 case D3DTOP_MODULATE4X:
2051 scale = scale * 2; /* Drop through */
2052 case D3DTOP_MODULATE2X:
2053 scale = scale * 2; /* Drop through */
2054 case D3DTOP_MODULATE:
2055 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2056 break;
2058 case D3DTOP_ADD:
2059 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2060 break;
2062 case D3DTOP_ADDSIGNED2X:
2063 scale = scale * 2; /* Drop through */
2064 case D3DTOP_ADDSIGNED:
2065 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2066 break;
2068 /* For the four blending modes, use the Arg2 parameter */
2069 case D3DTOP_BLENDDIFFUSEALPHA:
2070 case D3DTOP_BLENDTEXTUREALPHA:
2071 case D3DTOP_BLENDFACTORALPHA:
2072 case D3DTOP_BLENDCURRENTALPHA: {
2073 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2075 switch (dwState) {
2076 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2077 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2078 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
2079 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2082 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2083 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2084 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2085 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2086 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2087 } break;
2089 default:
2090 handled = FALSE;
2091 break;
2095 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2096 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2097 /* Switch the arguments if needed... */
2098 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2099 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2100 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2101 dwState);
2102 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2103 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2104 dwState);
2105 } else {
2106 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2107 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2108 dwState);
2109 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2110 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2111 dwState);
2115 if (handled) {
2116 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2117 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2118 } else {
2119 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2121 TRACE(" Stage type is : %s => %s\n", type, value);
2122 } else {
2123 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2125 } break;
2127 case D3DTSS_COLORARG1:
2128 case D3DTSS_COLORARG2:
2129 case D3DTSS_ALPHAARG1:
2130 case D3DTSS_ALPHAARG2: {
2131 const char *value, *value_comp = "", *value_alpha = "";
2132 BOOLEAN handled;
2133 D3DTEXTUREOP tex_op;
2135 switch (dwState & D3DTA_SELECTMASK) {
2136 #define GEN_CASE(a) case a: value = #a; break
2137 GEN_CASE(D3DTA_DIFFUSE);
2138 GEN_CASE(D3DTA_CURRENT);
2139 GEN_CASE(D3DTA_TEXTURE);
2140 GEN_CASE(D3DTA_TFACTOR);
2141 GEN_CASE(D3DTA_SPECULAR);
2142 #undef GEN_CASE
2143 default: value = "UNKNOWN";
2145 if (dwState & D3DTA_COMPLEMENT) {
2146 value_comp = " | D3DTA_COMPLEMENT";
2148 if (dwState & D3DTA_ALPHAREPLICATE) {
2149 value_alpha = " | D3DTA_ALPHAREPLICATE";
2152 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2153 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2154 } else {
2155 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2158 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2160 if (handled) {
2161 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2162 } else {
2163 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2165 } break;
2167 case D3DTSS_MIPMAPLODBIAS: {
2168 D3DVALUE value = *((D3DVALUE *) &dwState);
2169 BOOLEAN handled = TRUE;
2171 if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2172 handled = FALSE;
2174 if (handled) {
2175 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2176 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2177 } else {
2178 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2180 } break;
2182 case D3DTSS_MAXMIPLEVEL:
2183 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2184 break;
2186 case D3DTSS_BORDERCOLOR:
2187 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2188 ((dwState >> 16) & 0xFF),
2189 ((dwState >> 8) & 0xFF),
2190 ((dwState >> 0) & 0xFF),
2191 ((dwState >> 24) & 0xFF));
2192 break;
2194 case D3DTSS_TEXCOORDINDEX: {
2195 BOOLEAN handled = TRUE;
2196 const char *value;
2198 switch (dwState & 0xFFFF0000) {
2199 #define GEN_CASE(a) case a: value = #a; break
2200 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2201 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2202 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2203 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2204 #undef GEN_CASE
2205 default: value = "UNKNOWN";
2207 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2208 handled = FALSE;
2210 if (handled) {
2211 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2212 } else {
2213 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2215 } break;
2217 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2218 const char *projected = "", *value;
2219 BOOLEAN handled = TRUE;
2220 switch (dwState & 0xFF) {
2221 #define GEN_CASE(a) case a: value = #a; break
2222 GEN_CASE(D3DTTFF_DISABLE);
2223 GEN_CASE(D3DTTFF_COUNT1);
2224 GEN_CASE(D3DTTFF_COUNT2);
2225 GEN_CASE(D3DTTFF_COUNT3);
2226 GEN_CASE(D3DTTFF_COUNT4);
2227 #undef GEN_CASE
2228 default: value = "UNKNOWN";
2230 if (dwState & D3DTTFF_PROJECTED) {
2231 projected = " | D3DTTFF_PROJECTED";
2232 handled = FALSE;
2235 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2236 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2239 if (handled) {
2240 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2241 } else {
2242 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2244 } break;
2246 default:
2247 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2248 break;
2251 LEAVE_GL();
2253 return DD_OK;
2256 static DWORD
2257 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2259 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2260 DWORD stage;
2261 BOOLEAN enable_colorkey = FALSE;
2263 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2264 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2265 GLenum unit;
2267 /* If this stage is disabled, no need to go further... */
2268 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2269 break;
2271 /* First check if we need to bind any other texture for this stage */
2272 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2273 if (This->current_texture[stage] == NULL) {
2274 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2276 unit = GL_TEXTURE0_WINE + stage;
2277 if (unit != glThis->current_active_tex_unit) {
2278 GL_extensions.glActiveTexture(unit);
2279 glThis->current_active_tex_unit = unit;
2281 glBindTexture(GL_TEXTURE_2D, 0);
2282 glDisable(GL_TEXTURE_2D);
2283 } else {
2284 GLenum tex_name = gltex_get_tex_name(surf_ptr);
2286 unit = GL_TEXTURE0_WINE + stage;
2287 if (unit != glThis->current_active_tex_unit) {
2288 GL_extensions.glActiveTexture(unit);
2289 glThis->current_active_tex_unit = unit;
2292 if (glThis->current_bound_texture[stage] == NULL) {
2293 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2294 TRACE(" enabling 2D texturing and");
2295 glEnable(GL_TEXTURE_2D);
2298 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2299 glBindTexture(GL_TEXTURE_2D, tex_name);
2302 glThis->current_bound_texture[stage] = This->current_texture[stage];
2303 } else {
2304 if (glThis->current_bound_texture[stage] == NULL) {
2305 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2306 } else {
2307 TRACE(" using already bound texture id %d for stage %ld.\n",
2308 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2312 /* If no texure valid for this stage, go out of the loop */
2313 if (This->current_texture[stage] == NULL) break;
2315 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2316 This will also update the various texture parameters if needed.
2318 gltex_upload_texture(surf_ptr, This, stage);
2320 /* And finally check for color-keying (only on first stage) */
2321 if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2322 if (stage == 0) {
2323 enable_colorkey = TRUE;
2324 } else {
2325 static BOOL warn = FALSE;
2326 if (warn == FALSE) {
2327 warn = TRUE;
2328 WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2331 } else {
2332 if (stage == 0) {
2333 enable_colorkey = FALSE;
2338 /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2339 if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2340 (glThis->parent.version == 1)) &&
2341 (enable_colorkey)) {
2342 TRACE(" colorkey activated.\n");
2344 if (glThis->alpha_test == FALSE) {
2345 glEnable(GL_ALPHA_TEST);
2346 glThis->alpha_test = TRUE;
2348 if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2349 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1]) {
2350 static BOOL warn = FALSE;
2351 if (warn == FALSE) {
2352 warn = TRUE;
2353 WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2356 glThis->current_alpha_test_func = GL_NOTEQUAL;
2357 glThis->current_alpha_test_ref = 0.0;
2358 glAlphaFunc(GL_NOTEQUAL, 0.0);
2360 /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2361 Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2362 } else {
2363 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2364 glDisable(GL_ALPHA_TEST);
2365 glThis->alpha_test = FALSE;
2367 /* Maybe we should restore here the application-given alpha test states ? */
2370 return stage;
2373 HRESULT WINAPI
2374 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2375 DWORD dwStage,
2376 LPDIRECTDRAWSURFACE7 lpTexture2)
2378 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2380 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2382 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2383 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2384 if (lpTexture2 != NULL) {
2385 WARN(" setting a texture to a non-supported texture stage !\n");
2387 return DD_OK;
2390 if (This->current_texture[dwStage] != NULL) {
2391 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2394 if (lpTexture2 == NULL) {
2395 This->current_texture[dwStage] = NULL;
2396 } else {
2397 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2398 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2399 This->current_texture[dwStage] = tex_impl;
2402 return DD_OK;
2405 static HRESULT WINAPI
2406 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2407 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2409 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2410 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2412 fill_opengl_caps_7(lpD3DHELDevDesc);
2414 TRACE(" returning caps : no dump function yet.\n");
2416 return DD_OK;
2419 HRESULT WINAPI
2420 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2421 LPD3DMATERIAL7 lpMat)
2423 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2424 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2426 if (TRACE_ON(ddraw)) {
2427 TRACE(" material is : \n");
2428 dump_D3DMATERIAL7(lpMat);
2431 This->current_material = *lpMat;
2433 ENTER_GL();
2434 glMaterialfv(GL_FRONT_AND_BACK,
2435 GL_DIFFUSE,
2436 (float *) &(This->current_material.u.diffuse));
2437 glMaterialfv(GL_FRONT_AND_BACK,
2438 GL_AMBIENT,
2439 (float *) &(This->current_material.u1.ambient));
2440 glMaterialfv(GL_FRONT_AND_BACK,
2441 GL_SPECULAR,
2442 (float *) &(This->current_material.u2.specular));
2443 glMaterialfv(GL_FRONT_AND_BACK,
2444 GL_EMISSION,
2445 (float *) &(This->current_material.u3.emissive));
2446 glMaterialf(GL_FRONT_AND_BACK,
2447 GL_SHININESS,
2448 This->current_material.u4.power); /* Not sure about this... */
2449 LEAVE_GL();
2451 return DD_OK;
2454 static LPD3DLIGHT7 get_light(IDirect3DDeviceImpl *This, DWORD dwLightIndex)
2456 if (dwLightIndex >= This->num_set_lights)
2458 /* Extend, or allocate the light parameters array. */
2459 DWORD newlightnum = dwLightIndex + 1;
2460 LPD3DLIGHT7 newarrayptr = NULL;
2462 if (This->light_parameters)
2463 newarrayptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2464 This->light_parameters, newlightnum * sizeof(D3DLIGHT7));
2465 else
2466 newarrayptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2467 newlightnum * sizeof(D3DLIGHT7));
2469 if (!newarrayptr)
2470 return NULL;
2472 This->light_parameters = newarrayptr;
2473 This->num_set_lights = newlightnum;
2476 return &This->light_parameters[dwLightIndex];
2479 HRESULT WINAPI
2480 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2481 DWORD dwLightIndex,
2482 LPD3DLIGHT7 lpLight)
2484 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2485 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2486 LPD3DLIGHT7 lpdestlight = get_light( This, dwLightIndex );
2488 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2490 if (TRACE_ON(ddraw)) {
2491 TRACE(" setting light : \n");
2492 dump_D3DLIGHT7(lpLight);
2495 /* DirectX7 documentation states that this function can return
2496 DDERR_OUTOFMEMORY, so we do just that in case of an allocation
2497 error (which is the only reason why get_light() can fail). */
2498 if( !lpdestlight )
2499 return DDERR_OUTOFMEMORY;
2501 *lpdestlight = *lpLight;
2503 /* Some checks to print out nice warnings :-) */
2504 switch (lpLight->dltType) {
2505 case D3DLIGHT_DIRECTIONAL:
2506 case D3DLIGHT_POINT:
2507 /* These are handled properly... */
2508 break;
2510 case D3DLIGHT_SPOT:
2511 if ((lpLight->dvTheta != 0.0) ||
2512 (lpLight->dvTheta != lpLight->dvPhi)) {
2513 ERR("dvTheta not fully supported yet !\n");
2515 break;
2517 default:
2518 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2521 /* This will force the Light setting on next drawing of primitives */
2522 glThis->transform_state = GL_TRANSFORM_NONE;
2524 return DD_OK;
2527 HRESULT WINAPI
2528 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2529 DWORD dwLightIndex,
2530 BOOL bEnable)
2532 int lightslot = -1, i;
2533 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2534 LPD3DLIGHT7 lpdestlight = get_light(This, dwLightIndex);
2536 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2538 /* The DirectX doc isn't as explicit as for SetLight as whether we can
2539 return this from this function, but it doesn't state otherwise. */
2540 if (!lpdestlight)
2541 return DDERR_OUTOFMEMORY;
2543 /* If this light hasn't been set, initialise it with default values. */
2544 if (lpdestlight->dltType == 0)
2546 TRACE("setting default light parameters\n");
2548 /* We always use HEAP_ZERO_MEMORY when allocating the light_parameters
2549 array, so we only have to setup anything that shoud not be zero. */
2550 lpdestlight->dltType = D3DLIGHT_DIRECTIONAL;
2551 lpdestlight->dcvDiffuse.u1.r = 1.f;
2552 lpdestlight->dcvDiffuse.u2.g = 1.f;
2553 lpdestlight->dcvDiffuse.u3.b = 1.f;
2554 lpdestlight->dvDirection.u3.z = 1.f;
2557 /* Look for this light in the active lights array. */
2558 for (i = 0; i < This->max_active_lights; i++)
2559 if (This->active_lights[i] == dwLightIndex)
2561 lightslot = i;
2562 break;
2565 /* If we didn't find it, let's find the first available slot, if any. */
2566 if (lightslot == -1)
2567 for (i = 0; i < This->max_active_lights; i++)
2568 if (This->active_lights[i] == ~0)
2570 lightslot = i;
2571 break;
2574 ENTER_GL();
2575 if (bEnable) {
2576 if (lightslot == -1)
2578 /* This means that the app is trying to enable more lights than
2579 the maximum possible indicated in the caps.
2581 Windows actually let you do this, and disable one of the
2582 previously enabled lights to let you enable this one.
2584 It's not documented and I'm not sure how windows pick which light
2585 to disable to make room for this one. */
2586 FIXME("Enabling more light than the maximum is not supported yet.");
2587 return D3D_OK;
2590 glEnable(GL_LIGHT0 + lightslot);
2593 if (This->active_lights[lightslot] == ~0)
2595 /* This light gets active... Need to update its parameters to GL before the next drawing */
2596 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2598 This->active_lights[lightslot] = dwLightIndex;
2599 glThis->transform_state = GL_TRANSFORM_NONE;
2601 } else {
2602 glDisable(GL_LIGHT0 + lightslot);
2603 This->active_lights[lightslot] = ~0;
2606 LEAVE_GL();
2607 return DD_OK;
2610 HRESULT WINAPI
2611 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2613 IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2614 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2616 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2618 if (dwIndex >= This->max_clipping_planes) {
2619 return DDERR_INVALIDPARAMS;
2622 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2624 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2626 /* This is to force the reset of the transformation matrices on the next drawing.
2627 * This is needed to use the correct matrices for the various clipping planes.
2629 glThis->transform_state = GL_TRANSFORM_NONE;
2631 return D3D_OK;
2634 static HRESULT WINAPI
2635 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2636 LPD3DVIEWPORT7 lpData)
2638 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2639 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2641 if (TRACE_ON(ddraw)) {
2642 TRACE(" viewport is : \n");
2643 TRACE(" - dwX = %ld dwY = %ld\n",
2644 lpData->dwX, lpData->dwY);
2645 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2646 lpData->dwWidth, lpData->dwHeight);
2647 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2648 lpData->dvMinZ, lpData->dvMaxZ);
2650 ENTER_GL();
2652 /* Set the viewport */
2653 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2654 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2655 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2657 if ((lpData->dwX != This->active_viewport.dwX) ||
2658 (lpData->dwY != This->active_viewport.dwY) ||
2659 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2660 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2661 glViewport(lpData->dwX,
2662 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2663 lpData->dwWidth, lpData->dwHeight);
2666 LEAVE_GL();
2668 This->active_viewport = *lpData;
2670 return DD_OK;
2673 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2674 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2675 #else
2676 # define XCAST(fun) (void*)
2677 #endif
2679 static const IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2681 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2682 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2683 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2684 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2685 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2686 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2687 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2688 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2689 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2690 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2691 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2692 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2693 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2694 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2695 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2696 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2697 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2698 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2699 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2700 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2701 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2702 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2703 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2704 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2705 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2706 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2707 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2708 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2709 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2710 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2711 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2712 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2713 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2714 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2715 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2716 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2717 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2718 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2719 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2720 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2721 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2722 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2723 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2724 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2725 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2726 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2727 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2728 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2729 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2732 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2733 #undef XCAST
2734 #endif
2737 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2738 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2739 #else
2740 # define XCAST(fun) (void*)
2741 #endif
2743 static const IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2745 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2746 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2747 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2748 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2749 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2750 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2751 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2752 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2753 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2754 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2755 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2756 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2757 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2758 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2759 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2760 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2761 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2762 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2763 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2764 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2765 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2766 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2767 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2768 XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2769 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2770 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2771 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2772 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2773 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2774 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2775 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2776 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2777 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2778 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2779 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2780 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2781 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2782 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2783 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2784 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2785 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2786 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2789 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2790 #undef XCAST
2791 #endif
2794 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2795 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2796 #else
2797 # define XCAST(fun) (void*)
2798 #endif
2800 static const IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2802 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2803 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2804 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2805 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2806 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2807 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2808 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2809 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2810 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2811 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2812 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2813 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2814 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2815 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2816 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2817 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2818 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2819 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2820 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2821 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2822 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2823 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2824 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2825 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2826 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2827 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2828 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2829 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2830 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2831 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2832 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2833 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2834 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2837 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2838 #undef XCAST
2839 #endif
2842 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2843 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2844 #else
2845 # define XCAST(fun) (void*)
2846 #endif
2848 static const IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2850 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2851 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2852 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2853 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2854 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2855 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2856 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2857 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2858 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2859 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2860 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2861 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2862 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2863 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2864 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2865 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2866 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2867 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2868 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2869 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2870 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2871 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2874 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2875 #undef XCAST
2876 #endif
2878 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2879 WINE_GL_BUFFER_TYPE buffer_type,
2880 DWORD dwCount,
2881 LPD3DRECT lpRects,
2882 DWORD dwFlags,
2883 DWORD dwColor,
2884 D3DVALUE dvZ,
2885 DWORD dwStencil)
2887 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2888 GLbitfield bitfield = 0;
2889 D3DRECT rect;
2890 unsigned int i;
2892 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2893 if (TRACE_ON(ddraw)) {
2894 if (dwCount > 0) {
2895 unsigned int i;
2896 TRACE(" rectangles : \n");
2897 for (i = 0; i < dwCount; i++) {
2898 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2903 if (dwCount == 0) {
2904 dwCount = 1;
2905 rect.u1.x1 = 0;
2906 rect.u2.y1 = 0;
2907 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2908 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2909 lpRects = &rect;
2912 /* Clears the screen */
2913 ENTER_GL();
2915 if (dwFlags & D3DCLEAR_TARGET) {
2916 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2917 /* TODO: optimize here the case where Clear changes all the screen... */
2918 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2920 glThis->state[buffer_type] = SURFACE_GL;
2923 if (dwFlags & D3DCLEAR_ZBUFFER) {
2924 bitfield |= GL_DEPTH_BUFFER_BIT;
2925 if (glThis->depth_mask == FALSE) {
2926 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2928 if (dvZ != glThis->prev_clear_Z) {
2929 glClearDepth(dvZ);
2930 glThis->prev_clear_Z = dvZ;
2932 TRACE(" depth value : %f\n", dvZ);
2934 if (dwFlags & D3DCLEAR_STENCIL) {
2935 bitfield |= GL_STENCIL_BUFFER_BIT;
2936 if (dwStencil != glThis->prev_clear_stencil) {
2937 glClearStencil(dwStencil);
2938 glThis->prev_clear_stencil = dwStencil;
2940 TRACE(" stencil value : %ld\n", dwStencil);
2942 if (dwFlags & D3DCLEAR_TARGET) {
2943 bitfield |= GL_COLOR_BUFFER_BIT;
2944 if (dwColor != glThis->prev_clear_color) {
2945 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2946 ((dwColor >> 8) & 0xFF) / 255.0,
2947 ((dwColor >> 0) & 0xFF) / 255.0,
2948 ((dwColor >> 24) & 0xFF) / 255.0);
2949 glThis->prev_clear_color = dwColor;
2951 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2954 glEnable(GL_SCISSOR_TEST);
2955 for (i = 0; i < dwCount; i++) {
2956 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2957 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2958 glClear(bitfield);
2960 glDisable(GL_SCISSOR_TEST);
2962 if (dwFlags & D3DCLEAR_ZBUFFER) {
2963 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2966 LEAVE_GL();
2968 return DD_OK;
2971 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2972 DWORD dwCount,
2973 LPD3DRECT lpRects,
2974 DWORD dwFlags,
2975 DWORD dwColor,
2976 D3DVALUE dvZ,
2977 DWORD dwStencil)
2979 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2982 static HRESULT
2983 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2984 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2986 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2987 WINE_GL_BUFFER_TYPE buffer_type;
2989 /* First check if we BLT to the backbuffer... */
2990 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2991 buffer_type = WINE_GL_BUFFER_BACK;
2992 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2993 buffer_type = WINE_GL_BUFFER_FRONT;
2994 } else {
2995 ERR("Only BLT override to front or back-buffer is supported for now !\n");
2996 return DDERR_INVALIDPARAMS;
2999 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
3000 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
3001 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
3002 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
3003 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3004 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
3005 * GL to do it.
3007 return DDERR_INVALIDPARAMS;
3009 *buffer_type_p = buffer_type;
3011 return DD_OK;
3014 HRESULT
3015 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
3016 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
3017 DWORD dwFlags, LPDDBLTFX lpbltfx)
3019 WINE_GL_BUFFER_TYPE buffer_type;
3020 D3DRECT rect;
3022 if (rdst) {
3023 rect.u1.x1 = rdst->left;
3024 rect.u2.y1 = rdst->top;
3025 rect.u3.x2 = rdst->right;
3026 rect.u4.y2 = rdst->bottom;
3027 } else {
3028 rect.u1.x1 = 0;
3029 rect.u2.y1 = 0;
3030 rect.u3.x2 = This->surface_desc.dwWidth;
3031 rect.u4.y2 = This->surface_desc.dwHeight;
3034 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
3036 if (dwFlags & DDBLT_COLORFILL) {
3037 /* This is easy to handle for the D3D Device... */
3038 DWORD color;
3039 GLint prev_draw;
3041 /* The color as given in the Blt function is in the format of the frame-buffer...
3042 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3044 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
3045 if (This->palette) {
3046 color = ((0xFF000000) |
3047 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
3048 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
3049 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
3050 } else {
3051 color = 0xFF000000;
3053 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
3054 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3055 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3056 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3057 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3058 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3059 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3060 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
3061 color = 0xFFFFFFFF;
3062 } else {
3063 color = ((0xFF000000) |
3064 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
3065 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
3066 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
3068 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
3069 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
3070 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3071 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3072 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3073 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
3074 } else {
3075 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
3076 return DDERR_INVALIDPARAMS;
3078 } else {
3079 ERR("Wrong surface type for BLT override !\n");
3080 return DDERR_INVALIDPARAMS;
3083 TRACE(" executing D3D Device override.\n");
3085 ENTER_GL();
3087 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3088 if (buffer_type == WINE_GL_BUFFER_FRONT)
3089 glDrawBuffer(GL_FRONT);
3090 else
3091 glDrawBuffer(GL_BACK);
3093 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
3095 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3096 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3097 glDrawBuffer(prev_draw);
3099 LEAVE_GL();
3101 return DD_OK;
3102 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
3103 /* Normal blit without any special case... */
3104 if (src != NULL) {
3105 /* And which has a SRC surface */
3106 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3108 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3109 (src_impl->d3ddevice == This->d3ddevice) &&
3110 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3111 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3112 D3DRECT src_rect;
3113 int width, height;
3114 GLint prev_draw;
3115 WINE_GL_BUFFER_TYPE src_buffer_type;
3116 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3117 BOOLEAN initial;
3118 DWORD opt_bitmap;
3119 int x, y;
3121 if (rsrc) {
3122 src_rect.u1.x1 = rsrc->left;
3123 src_rect.u2.y1 = rsrc->top;
3124 src_rect.u3.x2 = rsrc->right;
3125 src_rect.u4.y2 = rsrc->bottom;
3126 } else {
3127 src_rect.u1.x1 = 0;
3128 src_rect.u2.y1 = 0;
3129 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3130 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3133 width = src_rect.u3.x2 - src_rect.u1.x1;
3134 height = src_rect.u4.y2 - src_rect.u2.y1;
3136 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3137 (height != (rect.u4.y2 - rect.u2.y1))) {
3138 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3139 return DDERR_INVALIDPARAMS;
3142 /* First check if we BLT from the backbuffer... */
3143 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3144 src_buffer_type = WINE_GL_BUFFER_BACK;
3145 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3146 src_buffer_type = WINE_GL_BUFFER_FRONT;
3147 } else {
3148 ERR("Unexpected case in direct buffer to buffer copy !\n");
3149 return DDERR_INVALIDPARAMS;
3152 TRACE(" using direct buffer to buffer copy.\n");
3154 ENTER_GL();
3156 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3158 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3159 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3160 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3161 LEAVE_GL();
3162 return DDERR_INVALIDPARAMS;
3165 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3166 if (buffer_type == WINE_GL_BUFFER_FRONT)
3167 glDrawBuffer(GL_FRONT);
3168 else
3169 glDrawBuffer(GL_BACK);
3171 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3172 glReadBuffer(GL_FRONT);
3173 else
3174 glReadBuffer(GL_BACK);
3176 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3177 And directly re-draws this on the destination buffer. */
3178 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3179 int get_height;
3181 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3182 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3183 else
3184 get_height = UNLOCK_TEX_SIZE;
3186 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3187 int get_width;
3189 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3190 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3191 else
3192 get_width = UNLOCK_TEX_SIZE;
3194 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3195 0, UNLOCK_TEX_SIZE - get_height,
3196 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3197 get_width, get_height);
3199 glBegin(GL_QUADS);
3200 glTexCoord2f(0.0, 0.0);
3201 glVertex3d(rect.u1.x1 + x,
3202 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3203 0.5);
3204 glTexCoord2f(1.0, 0.0);
3205 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3206 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3207 0.5);
3208 glTexCoord2f(1.0, 1.0);
3209 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3210 rect.u2.y1 + y,
3211 0.5);
3212 glTexCoord2f(0.0, 1.0);
3213 glVertex3d(rect.u1.x1 + x,
3214 rect.u2.y1 + y,
3215 0.5);
3216 glEnd();
3220 upload_surface_to_tex_memory_release();
3221 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3223 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3224 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3225 glDrawBuffer(prev_draw);
3227 LEAVE_GL();
3229 return DD_OK;
3230 } else {
3231 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3232 (this prevents calling glReadPixels) */
3233 D3DRECT src_rect;
3234 int width, height;
3235 GLint prev_draw;
3236 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3237 BOOLEAN initial;
3238 DWORD opt_bitmap;
3239 int x, y;
3240 double x_stretch, y_stretch;
3242 if (rsrc) {
3243 src_rect.u1.x1 = rsrc->left;
3244 src_rect.u2.y1 = rsrc->top;
3245 src_rect.u3.x2 = rsrc->right;
3246 src_rect.u4.y2 = rsrc->bottom;
3247 } else {
3248 src_rect.u1.x1 = 0;
3249 src_rect.u2.y1 = 0;
3250 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3251 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3254 width = src_rect.u3.x2 - src_rect.u1.x1;
3255 height = src_rect.u4.y2 - src_rect.u2.y1;
3257 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3258 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3260 TRACE(" using memory to buffer Blt override.\n");
3262 ENTER_GL();
3264 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3266 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3267 initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3268 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3269 LEAVE_GL();
3270 return DDERR_INVALIDPARAMS;
3273 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3274 if (buffer_type == WINE_GL_BUFFER_FRONT)
3275 glDrawBuffer(GL_FRONT);
3276 else
3277 glDrawBuffer(GL_BACK);
3279 /* Now the serious stuff happens. This is basically the same code as for the memory
3280 flush to frame buffer ... with stretching and different rectangles added :-) */
3281 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3282 RECT flush_rect;
3284 flush_rect.top = src_rect.u2.y1 + y;
3285 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3286 src_rect.u4.y2 :
3287 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3289 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3290 flush_rect.left = src_rect.u1.x1 + x;
3291 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3292 src_rect.u3.x2 :
3293 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3295 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3297 glBegin(GL_QUADS);
3298 glTexCoord2f(0.0, 0.0);
3299 glVertex3d(rect.u1.x1 + (x * x_stretch),
3300 rect.u2.y1 + (y * y_stretch),
3301 0.5);
3302 glTexCoord2f(1.0, 0.0);
3303 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3304 rect.u2.y1 + (y * y_stretch),
3305 0.5);
3306 glTexCoord2f(1.0, 1.0);
3307 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3308 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3309 0.5);
3310 glTexCoord2f(0.0, 1.0);
3311 glVertex3d(rect.u1.x1 + (x * x_stretch),
3312 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3313 0.5);
3314 glEnd();
3318 upload_surface_to_tex_memory_release();
3319 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3321 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3322 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3323 glDrawBuffer(prev_draw);
3325 LEAVE_GL();
3327 return DD_OK;
3331 return DDERR_INVALIDPARAMS;
3334 HRESULT
3335 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3336 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3337 LPRECT rsrc, DWORD trans)
3339 RECT rsrc2;
3340 RECT rdst;
3341 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3342 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3343 WINE_GL_BUFFER_TYPE buffer_type;
3344 GLint prev_draw;
3345 DWORD opt_bitmap;
3346 BOOLEAN initial;
3347 int width, height, x, y;
3349 /* Cannot support DSTCOLORKEY blitting... */
3350 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3352 if (rsrc == NULL) {
3353 WARN("rsrc is NULL - getting the whole surface !!\n");
3354 rsrc = &rsrc2;
3355 rsrc->left = rsrc->top = 0;
3356 rsrc->right = src_impl->surface_desc.dwWidth;
3357 rsrc->bottom = src_impl->surface_desc.dwHeight;
3358 } else {
3359 rsrc2 = *rsrc;
3360 rsrc = &rsrc2;
3363 rdst.left = dstx;
3364 rdst.top = dsty;
3365 rdst.right = dstx + (rsrc->right - rsrc->left);
3366 if (rdst.right > This->surface_desc.dwWidth) {
3367 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3368 rdst.right = This->surface_desc.dwWidth;
3370 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3371 if (rdst.bottom > This->surface_desc.dwHeight) {
3372 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3373 rdst.bottom = This->surface_desc.dwHeight;
3376 width = rsrc->right - rsrc->left;
3377 height = rsrc->bottom - rsrc->top;
3379 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3381 TRACE(" using BltFast memory to frame buffer override.\n");
3383 ENTER_GL();
3385 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3387 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3388 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3389 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3390 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3391 LEAVE_GL();
3392 return DDERR_INVALIDPARAMS;
3395 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3396 if (buffer_type == WINE_GL_BUFFER_FRONT)
3397 glDrawBuffer(GL_FRONT);
3398 else
3399 glDrawBuffer(GL_BACK);
3401 /* Now the serious stuff happens. This is basically the same code that for the memory
3402 flush to frame buffer but with different rectangles for source and destination :-) */
3403 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3404 RECT flush_rect;
3406 flush_rect.top = rsrc->top + y;
3407 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3408 rsrc->bottom :
3409 (rsrc->top + y + UNLOCK_TEX_SIZE));
3411 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3412 flush_rect.left = rsrc->left + x;
3413 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3414 rsrc->right :
3415 (rsrc->left + x + UNLOCK_TEX_SIZE));
3417 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3419 glBegin(GL_QUADS);
3420 glTexCoord2f(0.0, 0.0);
3421 glVertex3d(rdst.left + x,
3422 rdst.top + y,
3423 0.5);
3424 glTexCoord2f(1.0, 0.0);
3425 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3426 rdst.top + y,
3427 0.5);
3428 glTexCoord2f(1.0, 1.0);
3429 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3430 rdst.top + (y + UNLOCK_TEX_SIZE),
3431 0.5);
3432 glTexCoord2f(0.0, 1.0);
3433 glVertex3d(rdst.left + x,
3434 rdst.top + (y + UNLOCK_TEX_SIZE),
3435 0.5);
3436 glEnd();
3440 upload_surface_to_tex_memory_release();
3441 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3443 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3444 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3445 glDrawBuffer(prev_draw);
3447 LEAVE_GL();
3449 return DD_OK;
3452 void
3453 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3455 GLfloat height, width;
3456 GLfloat trans_mat[16];
3458 TRACE("(%p)\n", This);
3460 width = This->surface->surface_desc.dwWidth;
3461 height = This->surface->surface_desc.dwHeight;
3463 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3464 * to OpenGL screen coordinates (ie the upper left corner is not the same).
3466 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3467 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3468 #if 0
3469 /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3470 * that the Z coordinate needs to be given to GL unchanged.
3472 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 2.0; trans_mat[14] = -1.0;
3473 #endif
3474 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = 0.0;
3475 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3477 ENTER_GL();
3478 glMatrixMode(GL_MODELVIEW);
3479 glLoadIdentity();
3480 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3481 Correctness Tips section).
3483 Basically, from what I understood, if the game does not filter the font texture,
3484 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3485 one and we will have strange artifacts (as the rounding and stuff may give different results
3486 for different pixels, ie sometimes take the left pixel, sometimes the right).
3488 glTranslatef(0.375, 0.375, 0);
3489 glMatrixMode(GL_PROJECTION);
3490 glLoadMatrixf(trans_mat);
3491 LEAVE_GL();
3494 void
3495 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3496 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3498 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3500 ENTER_GL();
3501 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3502 glMatrixMode(GL_MODELVIEW);
3503 glLoadMatrixf((float *) view_mat);
3505 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3506 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3507 GLint i;
3508 DWORD runner;
3509 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3510 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3511 GLdouble plane[4];
3513 plane[0] = This->clipping_planes[i].plane[0];
3514 plane[1] = This->clipping_planes[i].plane[1];
3515 plane[2] = This->clipping_planes[i].plane[2];
3516 plane[3] = This->clipping_planes[i].plane[3];
3518 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3522 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3523 GLint i;
3525 for (i = 0; i < This->max_active_lights; i++ )
3527 DWORD dwLightIndex = This->active_lights[i];
3528 if (dwLightIndex != ~0)
3530 LPD3DLIGHT7 pLight = &This->light_parameters[dwLightIndex];
3531 switch (pLight->dltType)
3533 case D3DLIGHT_DIRECTIONAL: {
3534 float direction[4];
3535 float cut_off = 180.0;
3537 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3538 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3539 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3540 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3542 direction[0] = pLight->dvDirection.u1.x;
3543 direction[1] = pLight->dvDirection.u2.y;
3544 direction[2] = pLight->dvDirection.u3.z;
3545 direction[3] = 0.0;
3546 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3547 } break;
3549 case D3DLIGHT_POINT: {
3550 float position[4];
3551 float cut_off = 180.0;
3553 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3554 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3555 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3556 position[0] = pLight->dvPosition.u1.x;
3557 position[1] = pLight->dvPosition.u2.y;
3558 position[2] = pLight->dvPosition.u3.z;
3559 position[3] = 1.0;
3560 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3561 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3562 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3563 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3564 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3565 } break;
3567 case D3DLIGHT_SPOT: {
3568 float direction[4];
3569 float position[4];
3570 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3572 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3573 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3574 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3576 direction[0] = pLight->dvDirection.u1.x;
3577 direction[1] = pLight->dvDirection.u2.y;
3578 direction[2] = pLight->dvDirection.u3.z;
3579 direction[3] = 0.0;
3580 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3581 position[0] = pLight->dvPosition.u1.x;
3582 position[1] = pLight->dvPosition.u2.y;
3583 position[2] = pLight->dvPosition.u3.z;
3584 position[3] = 1.0;
3585 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3586 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3587 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3588 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3589 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3590 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &pLight->dvFalloff);
3591 } break;
3593 default:
3594 /* No warning here as it's already done at light setting */
3595 break;
3601 glMultMatrixf((float *) world_mat);
3603 if ((matrices & PROJMAT_CHANGED) != 0) {
3604 glMatrixMode(GL_PROJECTION);
3605 glLoadMatrixf((float *) proj_mat);
3607 LEAVE_GL();
3610 void
3611 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3613 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3614 DWORD tex_mat, tex_stage;
3616 TRACE("(%p,%08lx)\n", This, matrices);
3618 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3619 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3620 /* This will force an update of the transform state at the next drawing. */
3621 glThis->transform_state = GL_TRANSFORM_NONE;
3624 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3625 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3627 ENTER_GL();
3628 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3629 GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3630 if (matrices & tex_mat) {
3631 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3632 int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3634 if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3635 if (glThis->current_active_tex_unit != unit) {
3636 GL_extensions.glActiveTexture(unit);
3637 glThis->current_active_tex_unit = unit;
3639 glMatrixMode(GL_TEXTURE);
3640 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3642 This->tex_mat_is_identity[tex_stage] = is_identity;
3643 } else {
3644 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3645 if (glThis->current_active_tex_unit != unit) {
3646 GL_extensions.glActiveTexture(unit);
3647 glThis->current_active_tex_unit = unit;
3649 glMatrixMode(GL_TEXTURE);
3650 glLoadIdentity();
3651 This->tex_mat_is_identity[tex_stage] = TRUE;
3656 LEAVE_GL();
3660 /* TODO for both these functions :
3661 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3662 by other OpenGL code in D3D
3663 - handle the case where no 'Begin / EndScene' was done between two locks
3664 - handle the rectangles in the unlock too
3665 - handle pitch correctly...
3667 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3669 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3670 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3671 WINE_GL_BUFFER_TYPE buffer_type;
3672 RECT loc_rect;
3674 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3675 buffer_type = WINE_GL_BUFFER_FRONT;
3676 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3677 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3678 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3680 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3681 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3682 buffer_type = WINE_GL_BUFFER_BACK;
3683 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3684 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3685 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3687 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3688 } else {
3689 ERR("Wrong surface type for locking !\n");
3690 return;
3693 if (pRect == NULL) {
3694 loc_rect.top = 0;
3695 loc_rect.left = 0;
3696 loc_rect.bottom = This->surface_desc.dwHeight;
3697 loc_rect.right = This->surface_desc.dwWidth;
3698 pRect = &loc_rect;
3701 /* Try to acquire the device critical section */
3702 EnterCriticalSection(&(d3d_dev->crit));
3704 if (gl_d3d_dev->lock_rect_valid[buffer_type]) {
3705 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3706 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3708 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3710 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3711 /* Check if the new rectangle is in the previous one or not.
3712 If it is not, flush first the previous locks on screen.
3714 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3715 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3716 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3717 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3718 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3719 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3720 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3721 pRect->left, pRect->top, pRect->right, pRect->bottom,
3722 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3723 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3724 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3726 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3727 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3729 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3730 } else {
3731 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3734 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3735 /* If the surface is already in memory, no need to do anything here... */
3736 GLenum buffer_format;
3737 GLenum buffer_color;
3738 int y;
3739 char *dst;
3741 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3742 pRect->left, pRect->top, pRect->right, pRect->bottom);
3744 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3745 may only write to the device... But when we will blit it back to the screen, we need
3746 also to blit correctly the parts the application did not overwrite... */
3748 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3749 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3750 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3751 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3752 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3753 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3754 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3755 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3756 buffer_color = GL_RGB;
3757 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3758 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3759 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3760 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3761 buffer_format = GL_UNSIGNED_BYTE;
3762 buffer_color = GL_RGB;
3763 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3764 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3765 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3766 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3767 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3768 buffer_color = GL_BGRA;
3769 } else {
3770 ERR(" unsupported pixel format at device locking.\n");
3771 return;
3773 } else {
3774 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3775 return;
3778 ENTER_GL();
3780 if (buffer_type == WINE_GL_BUFFER_FRONT)
3781 /* Application wants to lock the front buffer */
3782 glReadBuffer(GL_FRONT);
3783 else
3784 /* Application wants to lock the back buffer */
3785 glReadBuffer(GL_BACK);
3787 dst = ((char *)This->surface_desc.lpSurface) +
3788 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3790 if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3791 /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3792 * could not be bothered considering the rare cases where it may be useful :-)
3794 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3795 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3796 y--) {
3797 glReadPixels(pRect->left, y,
3798 pRect->right - pRect->left, 1,
3799 buffer_color, buffer_format, dst);
3800 dst += This->surface_desc.u1.lPitch;
3802 } else {
3803 /* Faster path for surface copy. Note that I can use static variables here as I am
3804 * protected by the OpenGL critical section so this function won't be called by
3805 * two threads at the same time.
3807 static char *buffer = NULL;
3808 static int buffer_width = 0;
3809 char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3810 int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3812 glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3813 pRect->right - pRect->left, pRect->bottom - pRect->top,
3814 buffer_color, buffer_format, dst);
3816 if (current_width > buffer_width) {
3817 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3818 buffer_width = current_width;
3819 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3821 for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3822 memcpy(buffer, dst, current_width);
3823 memcpy(dst, dst2, current_width);
3824 memcpy(dst2, buffer, current_width);
3825 dst += This->surface_desc.u1.lPitch;
3826 dst2 -= This->surface_desc.u1.lPitch;
3830 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3832 #if 0
3833 /* I keep this code here as it's very useful to debug :-) */
3835 static int flush_count = 0;
3836 char buf[128];
3837 FILE *f;
3839 if ((++flush_count % 50) == 0) {
3840 sprintf(buf, "lock_%06d.pnm", flush_count);
3841 f = fopen(buf, "wb");
3842 DDRAW_dump_surface_to_disk(This, f);
3845 #endif
3847 LEAVE_GL();
3851 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3852 RECT loc_rect;
3853 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3854 int x, y;
3855 BOOLEAN initial;
3856 DWORD opt_bitmap;
3858 /* Note : no need here to lock the 'device critical section' as we are already protected by
3859 the GL critical section. */
3861 if (pRect == NULL) {
3862 loc_rect.top = 0;
3863 loc_rect.left = 0;
3864 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3865 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3866 pRect = &loc_rect;
3869 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3871 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3873 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3874 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3875 ERR(" unsupported pixel format at frame buffer flush.\n");
3876 return;
3879 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3880 RECT flush_rect;
3882 flush_rect.top = y;
3883 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3885 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3886 /* First, upload the texture... */
3887 flush_rect.left = x;
3888 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3890 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3892 glBegin(GL_QUADS);
3893 glTexCoord2f(0.0, 0.0);
3894 glVertex3d(x, y, 0.5);
3895 glTexCoord2f(1.0, 0.0);
3896 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3897 glTexCoord2f(1.0, 1.0);
3898 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3899 glTexCoord2f(0.0, 1.0);
3900 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3901 glEnd();
3905 upload_surface_to_tex_memory_release();
3906 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3908 #if 0
3909 /* I keep this code here as it's very useful to debug :-) */
3911 static int flush_count = 0;
3912 char buf[128];
3913 FILE *f;
3915 if ((++flush_count % 50) == 0) {
3916 sprintf(buf, "flush_%06d.pnm", flush_count);
3917 f = fopen(buf, "wb");
3918 DDRAW_dump_surface_to_disk(surf, f);
3921 #endif
3924 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3926 WINE_GL_BUFFER_TYPE buffer_type;
3927 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3928 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3930 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3931 buffer_type = WINE_GL_BUFFER_FRONT;
3932 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3933 buffer_type = WINE_GL_BUFFER_BACK;
3934 } else {
3935 ERR("Wrong surface type for locking !\n");
3936 return;
3939 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3940 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3941 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3943 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3945 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3946 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3947 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3948 GLint prev_draw;
3950 TRACE(" flushing front buffer immediately on screen.\n");
3952 ENTER_GL();
3953 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3954 glDrawBuffer(GL_FRONT);
3955 /* Note: we do not use the application provided lock rectangle but our own stored at
3956 lock time. This is because in old D3D versions, the 'lock' parameter did not
3957 exist.
3959 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]);
3960 glDrawBuffer(prev_draw);
3961 LEAVE_GL();
3962 } else {
3963 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3967 /* And 'frees' the device critical section */
3968 LeaveCriticalSection(&(d3d_dev->crit));
3971 static void
3972 apply_texture_state(IDirect3DDeviceImpl *This)
3974 int stage, state;
3976 /* Initialize texture stages states */
3977 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3978 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3979 if (This->state_block.set_flags.texture_stage_state[stage][state]) {
3980 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3981 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3987 HRESULT
3988 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, int version)
3990 IDirect3DDeviceImpl *object;
3991 IDirect3DDeviceGLImpl *gl_object;
3992 IDirectDrawSurfaceImpl *surf;
3993 HDC device_context;
3994 XVisualInfo *vis;
3995 int num;
3996 int tex_num;
3997 XVisualInfo template;
3998 GLenum buffer = GL_FRONT;
3999 int light;
4001 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
4002 if (object == NULL) return DDERR_OUTOFMEMORY;
4004 gl_object = (IDirect3DDeviceGLImpl *) object;
4006 object->ref = 1;
4007 object->d3d = d3d;
4008 object->surface = surface;
4009 object->set_context = set_context;
4010 object->clear = d3ddevice_clear_back;
4011 object->set_matrices = d3ddevice_set_matrices;
4012 object->matrices_updated = d3ddevice_matrices_updated;
4013 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
4014 object->version = version;
4016 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
4018 InitializeCriticalSection(&(object->crit));
4020 TRACE(" device critical section : %p\n", &(object->crit));
4022 device_context = GetDC(surface->ddraw_owner->window);
4023 gl_object->display = get_display(device_context);
4024 gl_object->drawable = get_drawable(device_context);
4025 ReleaseDC(surface->ddraw_owner->window,device_context);
4027 ENTER_GL();
4028 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
4029 vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
4030 if (vis == NULL) {
4031 HeapFree(GetProcessHeap(), 0, object);
4032 ERR("No visual found !\n");
4033 LEAVE_GL();
4034 return DDERR_INVALIDPARAMS;
4035 } else {
4036 TRACE(" visual found\n");
4039 gl_object->gl_context = glXCreateContext(gl_object->display, vis,
4040 NULL, GL_TRUE);
4042 if (gl_object->gl_context == NULL) {
4043 HeapFree(GetProcessHeap(), 0, object);
4044 ERR("Error in context creation !\n");
4045 LEAVE_GL();
4046 return DDERR_INVALIDPARAMS;
4047 } else {
4048 TRACE(" context created (%p)\n", gl_object->gl_context);
4051 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
4052 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4053 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
4054 surf->aux_ctx = (LPVOID) object;
4055 surf->aux_data = (LPVOID) gl_object->drawable;
4056 surf->aux_flip = opengl_flip;
4057 buffer = GL_BACK;
4058 break;
4061 /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
4062 if (surf == NULL) {
4063 TRACE(" no double buffering : drawing on the front buffer\n");
4064 buffer = GL_FRONT;
4067 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4068 IDirectDrawSurfaceImpl *surf2;
4069 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
4070 for (; surf2 != NULL; surf2 = surf2->next_attached) {
4071 TRACE(" checking surface %p :", surf2);
4072 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
4073 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
4074 /* Override the Lock / Unlock function for all these surfaces */
4075 surf2->lock_update_prev = surf2->lock_update;
4076 surf2->lock_update = d3ddevice_lock_update;
4077 surf2->unlock_update_prev = surf2->unlock_update;
4078 surf2->unlock_update = d3ddevice_unlock_update;
4079 /* And install also the blt / bltfast overrides */
4080 surf2->aux_blt = d3ddevice_blt;
4081 surf2->aux_bltfast = d3ddevice_bltfast;
4083 TRACE(" overriding direct surface access.\n");
4084 } else {
4085 TRACE(" no override.\n");
4087 surf2->d3ddevice = object;
4091 /* Set the various light parameters */
4092 object->num_set_lights = 0;
4093 object->max_active_lights = opengl_device_caps.dwMaxActiveLights;
4094 object->light_parameters = NULL;
4095 object->active_lights = HeapAlloc(GetProcessHeap(), 0,
4096 object->max_active_lights * sizeof(object->active_lights[0]));
4097 /* Fill the active light array with ~0, which is used to indicate an
4098 invalid light index. We don't use 0, because it's a valid light index. */
4099 for (light=0; light < object->max_active_lights; light++)
4100 object->active_lights[light] = ~0;
4103 /* Allocate memory for the matrices */
4104 object->world_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4105 object->view_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4106 object->proj_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4107 memcpy(object->world_mat, id_mat, 16 * sizeof(float));
4108 memcpy(object->view_mat , id_mat, 16 * sizeof(float));
4109 memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
4110 for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
4111 object->tex_mat[tex_num] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4112 memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
4113 object->tex_mat_is_identity[tex_num] = TRUE;
4116 /* Initialisation */
4117 TRACE(" setting current context\n");
4118 object->set_context(object);
4119 TRACE(" current context set\n");
4121 /* allocate the clipping planes */
4122 object->max_clipping_planes = opengl_device_caps.wMaxUserClipPlanes;
4123 object->clipping_planes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
4125 glHint(GL_FOG_HINT,GL_NICEST);
4127 /* Initialize the various GL contexts to be in sync with what we store locally */
4128 glClearDepth(0.0);
4129 glClearStencil(0);
4130 glClearColor(0.0, 0.0, 0.0, 0.0);
4131 glDepthMask(GL_TRUE);
4132 gl_object->depth_mask = TRUE;
4133 glEnable(GL_DEPTH_TEST);
4134 gl_object->depth_test = TRUE;
4135 glDisable(GL_ALPHA_TEST);
4136 glDisable(GL_STENCIL_TEST);
4137 glDisable(GL_CULL_FACE);
4138 glDisable(GL_LIGHTING);
4139 glDisable(GL_BLEND);
4140 glDisable(GL_FOG);
4141 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4142 gl_object->current_tex_env = GL_REPLACE;
4143 gl_object->current_active_tex_unit = GL_TEXTURE0_WINE;
4144 if (GL_extensions.glActiveTexture != NULL) {
4145 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
4147 gl_object->current_alpha_test_ref = 0.0;
4148 gl_object->current_alpha_test_func = GL_ALWAYS;
4149 glAlphaFunc(GL_ALWAYS, 0.0);
4151 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4152 glDrawBuffer(buffer);
4153 glReadBuffer(buffer);
4154 /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
4155 LEAVE_GL();
4157 gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
4158 gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
4160 /* fill_device_capabilities(d3d->ddraw); */
4162 ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
4163 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
4164 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
4165 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
4167 *obj = object;
4169 TRACE(" creating implementation at %p.\n", *obj);
4171 /* And finally warn D3D that this device is now present */
4172 object->d3d->d3d_added_device(object->d3d, object);
4174 InitDefaultStateBlock(&object->state_block, object->version);
4175 /* Apply default render state and texture stage state values */
4176 apply_render_state(object, &object->state_block);
4177 apply_texture_state(object);
4179 /* And fill the fog table with the default fog value */
4180 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4182 return DD_OK;
4185 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4187 pc->dwSize = sizeof(*pc);
4188 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4189 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4190 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4191 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4192 D3DPRASTERCAPS_ZFOG;
4193 if (GL_extensions.mipmap_lodbias) {
4194 pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4196 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4197 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4198 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4199 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4200 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4201 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4202 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4203 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4204 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4205 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4206 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4207 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4208 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4209 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4210 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4211 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4212 D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4213 D3DPTFILTERCAPS_MIPFPOINT;
4214 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4215 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4216 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4217 if (GL_extensions.mirrored_repeat) {
4218 pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4220 pc->dwStippleWidth = 32;
4221 pc->dwStippleHeight = 32;
4224 static void fill_caps(void)
4226 GLint max_clip_planes;
4227 GLint depth_bits;
4229 /* Fill first all the fields with default values which will be overriden later on with
4230 correct ones from the GL code
4232 opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4233 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4234 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4235 /* D3D 7 capabilities */
4236 D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4237 fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4238 fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4239 opengl_device_caps.dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
4240 opengl_device_caps.dwMinTextureWidth = 1;
4241 opengl_device_caps.dwMinTextureHeight = 1;
4242 opengl_device_caps.dwMaxTextureWidth = 1024;
4243 opengl_device_caps.dwMaxTextureHeight = 1024;
4244 opengl_device_caps.dwMaxTextureRepeat = 16;
4245 opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4246 opengl_device_caps.dwMaxAnisotropy = 0;
4247 opengl_device_caps.dvGuardBandLeft = 0.0;
4248 opengl_device_caps.dvGuardBandRight = 0.0;
4249 opengl_device_caps.dvGuardBandTop = 0.0;
4250 opengl_device_caps.dvGuardBandBottom = 0.0;
4251 opengl_device_caps.dvExtentsAdjust = 0.0;
4252 opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4253 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4254 opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4255 D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4256 D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4257 if (GL_extensions.max_texture_units != 0) {
4258 opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4259 opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4260 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4261 } else {
4262 opengl_device_caps.wMaxTextureBlendStages = 1;
4263 opengl_device_caps.wMaxSimultaneousTextures = 1;
4264 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4266 opengl_device_caps.dwMaxActiveLights = 16;
4267 opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4268 opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4269 opengl_device_caps.wMaxUserClipPlanes = 1;
4270 opengl_device_caps.wMaxVertexBlendMatrices = 0;
4271 opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4272 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4273 opengl_device_caps.dwReserved1 = 0;
4274 opengl_device_caps.dwReserved2 = 0;
4275 opengl_device_caps.dwReserved3 = 0;
4276 opengl_device_caps.dwReserved4 = 0;
4278 /* And now some GL overrides :-) */
4279 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4280 opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4281 opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4282 TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4284 glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4285 TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4287 glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4288 opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4289 TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4291 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4292 TRACE(": Z bits = %d\n", depth_bits);
4293 switch (depth_bits) {
4294 case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4295 case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4296 case 32:
4297 default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4301 BOOL
4302 d3ddevice_init_at_startup(void *gl_handle)
4304 XVisualInfo template;
4305 XVisualInfo *vis;
4306 HDC device_context;
4307 Display *display;
4308 Visual *visual;
4309 Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4310 XWindowAttributes win_attr;
4311 GLXContext gl_context;
4312 int num;
4313 const char *glExtensions;
4314 const char *glVersion;
4315 const char *glXExtensions = NULL;
4316 const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4317 int major, minor, patch, num_parsed;
4319 TRACE("Initializing GL...\n");
4321 if (!drawable)
4323 WARN("x11drv not loaded - D3D support disabled!\n");
4324 return FALSE;
4327 /* Get a default rendering context to have the 'caps' function query some info from GL */
4328 device_context = GetDC(0);
4329 display = get_display(device_context);
4330 ReleaseDC(0, device_context);
4332 ENTER_GL();
4333 if (XGetWindowAttributes(display, drawable, &win_attr)) {
4334 visual = win_attr.visual;
4335 } else {
4336 visual = DefaultVisual(display, DefaultScreen(display));
4338 template.visualid = XVisualIDFromVisual(visual);
4339 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4340 if (vis == NULL) {
4341 LEAVE_GL();
4342 WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4343 return FALSE;
4345 gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4346 XFree(vis);
4348 if (gl_context == NULL) {
4349 LEAVE_GL();
4350 WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4351 return FALSE;
4353 if (glXMakeCurrent(display, drawable, gl_context) == False) {
4354 glXDestroyContext(display, gl_context);
4355 LEAVE_GL();
4356 WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4357 return FALSE;
4360 /* Then, query all extensions */
4361 glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4362 glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4363 glVersion = (const char *) glGetString(GL_VERSION);
4364 if (gl_handle != NULL) {
4365 pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4368 /* Parse the GL version string */
4369 num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4370 if (num_parsed == 1) {
4371 minor = 0;
4372 patch = 0;
4373 } else if (num_parsed == 2) {
4374 patch = 0;
4376 TRACE("GL version %d.%d.%d\n", major, minor, patch);
4378 /* And starts to fill the extension context properly */
4379 memset(&GL_extensions, 0, sizeof(GL_extensions));
4380 TRACE("GL supports following extensions used by Wine :\n");
4382 /* Mirrored Repeat extension :
4383 - GL_ARB_texture_mirrored_repeat
4384 - GL_IBM_texture_mirrored_repeat
4385 - GL >= 1.4
4387 if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4388 (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4389 (major > 1) ||
4390 ((major == 1) && (minor >= 4))) {
4391 TRACE(" - mirrored repeat\n");
4392 GL_extensions.mirrored_repeat = TRUE;
4395 /* Texture LOD Bias :
4396 - GL_EXT_texture_lod_bias
4398 if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4399 TRACE(" - texture lod bias\n");
4400 GL_extensions.mipmap_lodbias = TRUE;
4403 /* For all subsequent extensions, we need glXGetProcAddress */
4404 if (pglXGetProcAddressARB != NULL) {
4405 /* Multi-texturing :
4406 - GL_ARB_multitexture
4407 - GL >= 1.2.1
4409 if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4410 (major > 1) ||
4411 ((major == 1) && (minor > 2)) ||
4412 ((major == 1) && (minor == 2) && (patch >= 1))) {
4413 glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4414 TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4415 /* We query the ARB version to be the most portable we can... */
4416 GL_extensions.glActiveTexture = pglXGetProcAddressARB( (const GLubyte *) "glActiveTextureARB");
4417 GL_extensions.glMultiTexCoord[0] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord1fvARB");
4418 GL_extensions.glMultiTexCoord[1] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord2fvARB");
4419 GL_extensions.glMultiTexCoord[2] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord3fvARB");
4420 GL_extensions.glMultiTexCoord[3] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord4fvARB");
4421 GL_extensions.glClientActiveTexture = pglXGetProcAddressARB( (const GLubyte *) "glClientActiveTextureARB");
4422 } else {
4423 GL_extensions.max_texture_units = 0;
4426 if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4427 TRACE(" - S3TC compression supported\n");
4428 GL_extensions.s3tc_compressed_texture = TRUE;
4429 GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB( (const GLubyte *) "glCompressedTexImage2DARB");
4430 GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB( (const GLubyte *) "glCompressedTexSubImage2DARB");
4434 /* Fill the D3D capabilities according to what GL tells us... */
4435 fill_caps();
4437 /* And frees this now-useless context */
4438 glXMakeCurrent(display, None, NULL);
4439 glXDestroyContext(display, gl_context);
4440 LEAVE_GL();
4442 return TRUE;