Added descriptions for a few more machine types.
[wine/multimedia.git] / dlls / ddraw / device_opengl.c
blob49bf1b06f59b9e402acafec3eea0b6c756794f87
1 /* Direct3D Device
2 * Copyright (c) 1998-2004 Lionel ULMER
3 * Copyright (c) 2002-2004 Christian Costa
5 * This file contains the MESA implementation of all the D3D devices that
6 * Wine supports.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <math.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "objbase.h"
37 #include "wingdi.h"
38 #include "ddraw.h"
39 #include "d3d.h"
40 #include "wine/debug.h"
41 #include "wine/library.h"
43 #include "d3d_private.h"
44 #include "opengl_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
47 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
49 /* x11drv GDI escapes */
50 #define X11DRV_ESCAPE 6789
51 enum x11drv_escape_codes
53 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
54 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
55 X11DRV_GET_FONT, /* get current X font for a DC */
58 /* They are non-static as they are used by Direct3D in the creation function */
59 const GUID IID_D3DDEVICE_OpenGL = {
60 0x31416d44,
61 0x86ae,
62 0x11d2,
63 { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
66 const float id_mat[16] = {
67 1.0, 0.0, 0.0, 0.0,
68 0.0, 1.0, 0.0, 0.0,
69 0.0, 0.0, 1.0, 0.0,
70 0.0, 0.0, 0.0, 1.0
73 /* This is filled at DLL loading time */
74 static D3DDEVICEDESC7 opengl_device_caps;
75 GL_EXTENSIONS_LIST GL_extensions;
77 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
78 D3DPRIMITIVETYPE d3dptPrimitiveType,
79 DWORD d3dvtVertexType,
80 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
81 DWORD dwVertexCount,
82 LPWORD dwIndices,
83 DWORD dwIndexCount,
84 DWORD dwFlags) ;
86 static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
88 /* retrieve the X display to use on a given DC */
89 inline static Display *get_display( HDC hdc )
91 Display *display;
92 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
94 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
95 sizeof(display), (LPSTR)&display )) display = NULL;
97 return display;
100 #define UNLOCK_TEX_SIZE 256
102 #define DEPTH_RANGE_BIT (0x00000001 << 0)
103 #define VIEWPORT_BIT (0x00000001 << 1)
105 static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
106 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
107 DWORD opt_bitmap = 0x00000000;
109 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
110 ((d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE))) {
111 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
112 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
113 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
115 /* Disable multi-texturing for level 1 to disable all others */
116 glDisable(GL_TEXTURE_2D);
118 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
119 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
120 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
122 if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
123 (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
124 glEnable(GL_TEXTURE_2D);
125 if (gl_d3d_dev->unlock_tex == 0) {
126 glGenTextures(1, &gl_d3d_dev->unlock_tex);
127 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
128 *initial = TRUE;
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
133 } else {
134 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
135 *initial = FALSE;
137 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
138 glMatrixMode(GL_TEXTURE);
139 glLoadIdentity();
142 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
143 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
144 d3ddevice_set_ortho(d3d_dev);
147 if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
148 glEnable(GL_SCISSOR_TEST);
149 if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
150 (d3d_dev->active_viewport.dvMaxZ != 1.0)) {
151 glDepthRange(0.0, 1.0);
152 opt_bitmap |= DEPTH_RANGE_BIT;
154 if ((d3d_dev->active_viewport.dwX != 0) ||
155 (d3d_dev->active_viewport.dwY != 0) ||
156 (d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
157 (d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
158 glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
159 opt_bitmap |= VIEWPORT_BIT;
161 glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
162 pRect->right - pRect->left, pRect->bottom - pRect->top);
163 if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
164 if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
165 if (use_alpha) {
166 if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
167 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
168 glAlphaFunc(GL_NOTEQUAL, 0.0);
169 } else {
170 if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
172 if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
173 if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
174 if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
175 if (gl_d3d_dev->current_tex_env != GL_REPLACE)
176 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
178 return opt_bitmap;
181 static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
182 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
184 /* And restore all the various states modified by this code */
185 if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
186 if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
187 if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
188 glEnable(GL_ALPHA_TEST);
189 else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
190 glDisable(GL_ALPHA_TEST);
191 if (use_alpha) {
192 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
193 glAlphaFunc(gl_d3d_dev->current_alpha_test_func, gl_d3d_dev->current_alpha_test_ref);
195 if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
196 if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
197 if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
198 if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
199 glDisable(GL_SCISSOR_TEST);
200 if (opt_bitmap & DEPTH_RANGE_BIT) {
201 glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
203 if (opt_bitmap & VIEWPORT_BIT) {
204 glViewport(d3d_dev->active_viewport.dwX,
205 d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
206 d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
208 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
209 d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
212 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
213 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
214 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
216 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
217 /* Note that here we could directly re-bind the previous texture... But it would in some case be a spurious
218 bind if ever the game changes the texture just after.
220 So choose 0x00000001 to postpone the binding to the next time we draw something on screen. */
221 gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
222 if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
224 /* And re-enabled if needed texture level 1 */
225 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
226 (d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
227 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
228 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
229 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
231 glEnable(GL_TEXTURE_2D);
235 /* retrieve the X drawable to use on a given DC */
236 inline static Drawable get_drawable( HDC hdc )
238 Drawable drawable;
239 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
241 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
242 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
244 return drawable;
247 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
249 IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
250 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
252 TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
253 ENTER_GL();
254 if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
255 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]);
257 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
258 gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
259 glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
260 LEAVE_GL();
262 return TRUE;
266 /*******************************************************************************
267 * OpenGL static functions
269 static void set_context(IDirect3DDeviceImpl* This)
271 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
273 TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
274 ENTER_GL();
275 if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
276 ERR("Error in setting current context (context %p drawable %ld)!\n",
277 glThis->gl_context, glThis->drawable);
279 LEAVE_GL();
282 static void fill_opengl_caps(D3DDEVICEDESC *d1)
284 d1->dwSize = sizeof(*d1);
285 d1->dwFlags = D3DDD_COLORMODEL | D3DDD_DEVCAPS | D3DDD_TRANSFORMCAPS | D3DDD_BCLIPPING | D3DDD_LIGHTINGCAPS |
286 D3DDD_LINECAPS | D3DDD_TRICAPS | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH |
287 D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT;
288 d1->dcmColorModel = D3DCOLOR_RGB;
289 d1->dwDevCaps = opengl_device_caps.dwDevCaps;
290 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
291 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
292 d1->bClipping = TRUE;
293 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
294 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
295 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
296 d1->dlcLightingCaps.dwNumLights = opengl_device_caps.dwMaxActiveLights;
297 d1->dpcLineCaps = opengl_device_caps.dpcLineCaps;
298 d1->dpcTriCaps = opengl_device_caps.dpcTriCaps;
299 d1->dwDeviceRenderBitDepth = opengl_device_caps.dwDeviceRenderBitDepth;
300 d1->dwDeviceZBufferBitDepth = opengl_device_caps.dwDeviceZBufferBitDepth;
301 d1->dwMaxBufferSize = 0;
302 d1->dwMaxVertexCount = 65536;
303 d1->dwMinTextureWidth = opengl_device_caps.dwMinTextureWidth;
304 d1->dwMinTextureHeight = opengl_device_caps.dwMinTextureHeight;
305 d1->dwMaxTextureWidth = opengl_device_caps.dwMaxTextureWidth;
306 d1->dwMaxTextureHeight = opengl_device_caps.dwMaxTextureHeight;
307 d1->dwMinStippleWidth = 1;
308 d1->dwMinStippleHeight = 1;
309 d1->dwMaxStippleWidth = 32;
310 d1->dwMaxStippleHeight = 32;
311 d1->dwMaxTextureRepeat = opengl_device_caps.dwMaxTextureRepeat;
312 d1->dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureAspectRatio;
313 d1->dwMaxAnisotropy = opengl_device_caps.dwMaxAnisotropy;
314 d1->dvGuardBandLeft = opengl_device_caps.dvGuardBandLeft;
315 d1->dvGuardBandRight = opengl_device_caps.dvGuardBandRight;
316 d1->dvGuardBandTop = opengl_device_caps.dvGuardBandTop;
317 d1->dvGuardBandBottom = opengl_device_caps.dvGuardBandBottom;
318 d1->dvExtentsAdjust = opengl_device_caps.dvExtentsAdjust;
319 d1->dwStencilCaps = opengl_device_caps.dwStencilCaps;
320 d1->dwFVFCaps = opengl_device_caps.dwFVFCaps;
321 d1->dwTextureOpCaps = opengl_device_caps.dwTextureOpCaps;
322 d1->wMaxTextureBlendStages = opengl_device_caps.wMaxTextureBlendStages;
323 d1->wMaxSimultaneousTextures = opengl_device_caps.wMaxSimultaneousTextures;
326 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
328 *d = opengl_device_caps;
331 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
333 D3DDEVICEDESC dref, d1, d2;
334 HRESULT ret_value;
336 /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
337 Let's put the string in a sufficiently sized array in writable memory. */
338 char device_name[50];
339 strcpy(device_name,"direct3d");
341 fill_opengl_caps(&dref);
343 if (version > 1) {
344 /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
345 char interface_name[] = "WINE Reference Direct3DX using OpenGL";
346 TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
347 d1 = dref;
348 d2 = dref;
349 ret_value = cb((LPIID) &IID_IDirect3DRefDevice, interface_name, device_name, &d1, &d2, context);
350 if (ret_value != D3DENUMRET_OK)
351 return ret_value;
355 char interface_name[] = "WINE Direct3DX using OpenGL";
356 TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
357 d1 = dref;
358 d2 = dref;
359 ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, interface_name, device_name, &d1, &d2, context);
360 if (ret_value != D3DENUMRET_OK)
361 return ret_value;
364 return D3DENUMRET_OK;
367 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
369 D3DDEVICEDESC7 ddesc;
370 char interface_name[] = "WINE Direct3D7 using OpenGL";
371 char device_name[] = "Wine D3D7 device";
373 fill_opengl_caps_7(&ddesc);
375 TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
377 return cb(interface_name, device_name, &ddesc, context);
380 static ULONG WINAPI
381 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
383 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
384 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
385 ULONG ref = InterlockedDecrement(&This->ref);
387 TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, ref + 1);
389 if (!ref) {
390 int i;
391 IDirectDrawSurfaceImpl *surface = This->surface, *surf;
393 /* Release texture associated with the device */
394 for (i = 0; i < MAX_TEXTURES; i++) {
395 if (This->current_texture[i] != NULL)
396 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
397 HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
400 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
401 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
402 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
403 surf->aux_ctx = NULL;
404 surf->aux_data = NULL;
405 surf->aux_flip = NULL;
406 break;
409 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
410 IDirectDrawSurfaceImpl *surf2;
411 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
412 for (; surf2 != NULL; surf2 = surf2->next_attached) {
413 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
414 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
415 /* Override the Lock / Unlock function for all these surfaces */
416 surf2->lock_update = surf2->lock_update_prev;
417 surf2->unlock_update = surf2->unlock_update_prev;
418 /* And install also the blt / bltfast overrides */
419 surf2->aux_blt = NULL;
420 surf2->aux_bltfast = NULL;
422 surf2->d3ddevice = NULL;
426 /* And warn the D3D object that this device is no longer active... */
427 This->d3d->d3d_removed_device(This->d3d, This);
429 /* Free light arrays */
430 if (This->light_parameters)
431 HeapFree(GetProcessHeap(), 0, This->light_parameters);
432 HeapFree(GetProcessHeap(), 0, This->active_lights);
434 HeapFree(GetProcessHeap(), 0, This->world_mat);
435 HeapFree(GetProcessHeap(), 0, This->view_mat);
436 HeapFree(GetProcessHeap(), 0, This->proj_mat);
438 if (glThis->surface_ptr)
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);
450 HeapFree(GetProcessHeap(), 0, This);
451 return 0;
453 return ref;
456 HRESULT WINAPI
457 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
458 LPD3DDEVICEDESC lpD3DHWDevDesc,
459 LPD3DDEVICEDESC lpD3DHELDevDesc)
461 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
462 D3DDEVICEDESC desc;
463 DWORD dwSize;
465 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
467 fill_opengl_caps(&desc);
468 dwSize = lpD3DHWDevDesc->dwSize;
469 memset(lpD3DHWDevDesc, 0, dwSize);
470 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
472 dwSize = lpD3DHELDevDesc->dwSize;
473 memset(lpD3DHELDevDesc, 0, dwSize);
474 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
476 TRACE(" returning caps : (no dump function yet)\n");
478 return DD_OK;
481 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
482 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
483 LPVOID context, int version)
485 DDSURFACEDESC sdesc;
486 LPDDPIXELFORMAT pformat;
488 /* Do the texture enumeration */
489 sdesc.dwSize = sizeof(DDSURFACEDESC);
490 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
491 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
492 pformat = &(sdesc.ddpfPixelFormat);
493 pformat->dwSize = sizeof(DDPIXELFORMAT);
494 pformat->dwFourCC = 0;
496 TRACE("Enumerating GL_RGBA unpacked (32)\n");
497 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
498 pformat->u1.dwRGBBitCount = 32;
499 pformat->u2.dwRBitMask = 0x00FF0000;
500 pformat->u3.dwGBitMask = 0x0000FF00;
501 pformat->u4.dwBBitMask = 0x000000FF;
502 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
503 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
504 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
506 TRACE("Enumerating GL_RGB unpacked (32)\n");
507 pformat->dwFlags = DDPF_RGB;
508 pformat->u1.dwRGBBitCount = 32;
509 pformat->u2.dwRBitMask = 0x00FF0000;
510 pformat->u3.dwGBitMask = 0x0000FF00;
511 pformat->u4.dwBBitMask = 0x000000FF;
512 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
513 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
514 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
516 TRACE("Enumerating GL_RGB unpacked (24)\n");
517 pformat->dwFlags = DDPF_RGB;
518 pformat->u1.dwRGBBitCount = 24;
519 pformat->u2.dwRBitMask = 0x00FF0000;
520 pformat->u3.dwGBitMask = 0x0000FF00;
521 pformat->u4.dwBBitMask = 0x000000FF;
522 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
523 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
524 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
526 /* Note : even if this is an 'emulated' texture format, it needs to be first
527 as some dumb applications seem to rely on that. */
528 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
529 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
530 pformat->u1.dwRGBBitCount = 16;
531 pformat->u2.dwRBitMask = 0x00007C00;
532 pformat->u3.dwGBitMask = 0x000003E0;
533 pformat->u4.dwBBitMask = 0x0000001F;
534 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
535 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
536 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
538 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
539 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
540 pformat->u1.dwRGBBitCount = 16;
541 pformat->u2.dwRBitMask = 0x00000F00;
542 pformat->u3.dwGBitMask = 0x000000F0;
543 pformat->u4.dwBBitMask = 0x0000000F;
544 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
545 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
546 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
548 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
549 pformat->dwFlags = DDPF_RGB;
550 pformat->u1.dwRGBBitCount = 16;
551 pformat->u2.dwRBitMask = 0x0000F800;
552 pformat->u3.dwGBitMask = 0x000007E0;
553 pformat->u4.dwBBitMask = 0x0000001F;
554 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
555 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
556 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
558 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
559 pformat->dwFlags = DDPF_RGB;
560 pformat->u1.dwRGBBitCount = 16;
561 pformat->u2.dwRBitMask = 0x00007C00;
562 pformat->u3.dwGBitMask = 0x000003E0;
563 pformat->u4.dwBBitMask = 0x0000001F;
564 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
565 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
566 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
568 #if 0
569 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
570 find enumerated, others the last one. And both want to have the ARGB one.
572 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
574 /* See argument about the RGBA format for 'packed' texture formats */
575 TRACE("Enumerating GL_RGBA unpacked (32)\n");
576 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
577 pformat->u1.dwRGBBitCount = 32;
578 pformat->u2.dwRBitMask = 0xFF000000;
579 pformat->u3.dwGBitMask = 0x00FF0000;
580 pformat->u4.dwBBitMask = 0x0000FF00;
581 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
582 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
583 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
585 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
586 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
587 pformat->u1.dwRGBBitCount = 16;
588 pformat->u2.dwRBitMask = 0x0000F000;
589 pformat->u3.dwGBitMask = 0x00000F00;
590 pformat->u4.dwBBitMask = 0x000000F0;
591 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
592 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
593 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
595 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
596 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
597 pformat->u1.dwRGBBitCount = 16;
598 pformat->u2.dwRBitMask = 0x0000F800;
599 pformat->u3.dwGBitMask = 0x000007C0;
600 pformat->u4.dwBBitMask = 0x0000003E;
601 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
602 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
603 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
604 #endif
606 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
607 pformat->dwFlags = DDPF_RGB;
608 pformat->u1.dwRGBBitCount = 8;
609 pformat->u2.dwRBitMask = 0x000000E0;
610 pformat->u3.dwGBitMask = 0x0000001C;
611 pformat->u4.dwBBitMask = 0x00000003;
612 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
613 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
614 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
616 TRACE("Enumerating Paletted (8)\n");
617 pformat->dwFlags = DDPF_PALETTEINDEXED8;
618 pformat->u1.dwRGBBitCount = 8;
619 pformat->u2.dwRBitMask = 0x00000000;
620 pformat->u3.dwGBitMask = 0x00000000;
621 pformat->u4.dwBBitMask = 0x00000000;
622 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
623 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
624 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
626 /* DXT textures only exist for devices created from IDirect3D3 and above */
627 if ((version >= 3) && GL_extensions.s3tc_compressed_texture) {
628 TRACE("Enumerating DXT1\n");
629 pformat->dwFlags = DDPF_FOURCC;
630 pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
631 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
632 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
634 TRACE("Enumerating DXT3\n");
635 pformat->dwFlags = DDPF_FOURCC;
636 pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
637 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
638 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
640 TRACE("Enumerating DXT5\n");
641 pformat->dwFlags = DDPF_FOURCC;
642 pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
643 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
644 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
647 TRACE("End of enumeration\n");
648 return DD_OK;
652 HRESULT
653 d3ddevice_find(IDirectDrawImpl *d3d,
654 LPD3DFINDDEVICESEARCH lpD3DDFS,
655 LPD3DFINDDEVICERESULT lplpD3DDevice)
657 D3DDEVICEDESC desc;
659 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
660 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
661 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
662 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
664 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
665 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
666 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
667 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
668 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
669 TRACE(" no match for this GUID.\n");
670 return DDERR_INVALIDPARAMS;
674 /* Now return our own GUID */
675 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
676 fill_opengl_caps(&desc);
677 lplpD3DDevice->ddHwDesc = desc;
678 lplpD3DDevice->ddSwDesc = desc;
680 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
682 return D3D_OK;
685 HRESULT WINAPI
686 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
687 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
688 LPVOID lpArg)
690 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
691 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
692 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg, This->version);
695 static HRESULT WINAPI
696 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
697 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
698 LPVOID lpArg)
700 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
701 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
702 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg, This->version);
705 static HRESULT WINAPI
706 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
707 D3DRENDERSTATETYPE dwRenderStateType,
708 DWORD dwRenderState)
710 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
711 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
713 /* Call the render state functions */
714 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
715 set_render_state(This, dwRenderStateType, &This->state_block);
717 return DD_OK;
720 static HRESULT WINAPI
721 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
722 D3DRENDERSTATETYPE dwRenderStateType,
723 LPDWORD lpdwRenderState)
725 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
726 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
728 /* Call the render state functions */
729 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
731 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
733 return DD_OK;
736 static HRESULT WINAPI
737 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
738 D3DLIGHTSTATETYPE dwLightStateType,
739 LPDWORD lpdwLightState)
741 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
743 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
745 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
746 TRACE("Unexpected Light State Type\n");
747 return DDERR_INVALIDPARAMS;
750 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
751 *lpdwLightState = This->material;
752 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
753 *lpdwLightState = D3DCOLOR_RGB;
754 } else {
755 D3DRENDERSTATETYPE rs;
756 switch (dwLightStateType) {
757 case D3DLIGHTSTATE_AMBIENT: /* 2 */
758 rs = D3DRENDERSTATE_AMBIENT;
759 break;
760 case D3DLIGHTSTATE_FOGMODE: /* 4 */
761 rs = D3DRENDERSTATE_FOGVERTEXMODE;
762 break;
763 case D3DLIGHTSTATE_FOGSTART: /* 5 */
764 rs = D3DRENDERSTATE_FOGSTART;
765 break;
766 case D3DLIGHTSTATE_FOGEND: /* 6 */
767 rs = D3DRENDERSTATE_FOGEND;
768 break;
769 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
770 rs = D3DRENDERSTATE_FOGDENSITY;
771 break;
772 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
773 rs = D3DRENDERSTATE_COLORVERTEX;
774 break;
775 default:
776 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
777 return DDERR_INVALIDPARAMS;
780 IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
781 rs,lpdwLightState);
784 return DD_OK;
787 static HRESULT WINAPI
788 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
789 D3DLIGHTSTATETYPE dwLightStateType,
790 DWORD dwLightState)
792 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
794 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
796 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
797 TRACE("Unexpected Light State Type\n");
798 return DDERR_INVALIDPARAMS;
801 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
802 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
804 if (mat != NULL) {
805 TRACE(" activating material %p.\n", mat);
806 mat->activate(mat);
807 } else {
808 FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
810 This->material = dwLightState;
811 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
812 switch (dwLightState) {
813 case D3DCOLOR_MONO:
814 ERR("DDCOLOR_MONO should not happen!\n");
815 break;
816 case D3DCOLOR_RGB:
817 /* We are already in this mode */
818 TRACE("Setting color model to RGB (no-op).\n");
819 break;
820 default:
821 ERR("Unknown color model!\n");
822 return DDERR_INVALIDPARAMS;
824 } else {
825 D3DRENDERSTATETYPE rs;
826 switch (dwLightStateType) {
827 case D3DLIGHTSTATE_AMBIENT: /* 2 */
828 rs = D3DRENDERSTATE_AMBIENT;
829 break;
830 case D3DLIGHTSTATE_FOGMODE: /* 4 */
831 rs = D3DRENDERSTATE_FOGVERTEXMODE;
832 break;
833 case D3DLIGHTSTATE_FOGSTART: /* 5 */
834 rs = D3DRENDERSTATE_FOGSTART;
835 break;
836 case D3DLIGHTSTATE_FOGEND: /* 6 */
837 rs = D3DRENDERSTATE_FOGEND;
838 break;
839 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
840 rs = D3DRENDERSTATE_FOGDENSITY;
841 break;
842 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
843 rs = D3DRENDERSTATE_COLORVERTEX;
844 break;
845 default:
846 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
847 return DDERR_INVALIDPARAMS;
850 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
851 rs,dwLightState);
854 return DD_OK;
857 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
859 switch (d3dpt) {
860 case D3DPT_POINTLIST:
861 TRACE(" primitive type is POINTS\n");
862 return GL_POINTS;
864 case D3DPT_LINELIST:
865 TRACE(" primitive type is LINES\n");
866 return GL_LINES;
868 case D3DPT_LINESTRIP:
869 TRACE(" primitive type is LINE_STRIP\n");
870 return GL_LINE_STRIP;
872 case D3DPT_TRIANGLELIST:
873 TRACE(" primitive type is TRIANGLES\n");
874 return GL_TRIANGLES;
876 case D3DPT_TRIANGLESTRIP:
877 TRACE(" primitive type is TRIANGLE_STRIP\n");
878 return GL_TRIANGLE_STRIP;
880 case D3DPT_TRIANGLEFAN:
881 TRACE(" primitive type is TRIANGLE_FAN\n");
882 return GL_TRIANGLE_FAN;
884 default:
885 FIXME("Unhandled primitive %08x\n", d3dpt);
886 return GL_POINTS;
890 /* This function calculate the Z coordinate from Zproj */
891 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
893 float a,b,c,d;
894 /* Assume that X = Y = 0 and W = 1 */
895 a = This->proj_mat->_33;
896 b = This->proj_mat->_34;
897 c = This->proj_mat->_43;
898 d = This->proj_mat->_44;
899 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
900 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
901 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
903 return (d*Zproj - c) / (a - b*Zproj);
906 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
907 int i;
909 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
911 for (i = 0; i < 3; i++) {
912 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
913 DWORD elt;
914 for (elt = 0; elt < 0x10000; elt++) {
915 /* We apply the fog transformation and cache the result */
916 DWORD fog_intensity = elt & 0xFF;
917 DWORD vertex_color = (elt >> 8) & 0xFF;
918 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
923 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
924 BOOLEAN vertex_transformed,
925 BOOLEAN vertex_lit) {
926 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
928 /* Puts GL in the correct lighting / transformation mode */
929 if ((vertex_transformed == FALSE) &&
930 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
931 /* Need to put the correct transformation again if we go from Transformed
932 vertices to non-transformed ones.
934 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
935 This->world_mat, This->view_mat, This->proj_mat);
936 glThis->transform_state = GL_TRANSFORM_NORMAL;
938 } else if (vertex_transformed &&
939 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
940 /* Set our orthographic projection */
941 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
942 glThis->transform_state = GL_TRANSFORM_ORTHO;
943 d3ddevice_set_ortho(This);
947 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
948 if no fogging state change occurred */
949 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
950 if (vertex_transformed) {
951 if (glThis->fogging != 0) {
952 glDisable(GL_FOG);
953 glThis->fogging = 0;
955 /* Now check if our fog_table still corresponds to the current vertex color.
956 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
957 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
958 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
959 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
960 /* We need to rebuild our fog table.... */
961 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
963 } else {
964 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
965 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
966 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
967 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
968 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
970 if (vertex_lit == FALSE) {
971 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
972 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
973 } else {
974 /* Special case of 'pixel fog' */
975 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
976 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
978 if (glThis->fogging == 0) {
979 glEnable(GL_FOG);
980 glThis->fogging = 1;
982 } else {
983 if (glThis->fogging != 0) {
984 glDisable(GL_FOG);
985 glThis->fogging = 0;
989 } else {
990 if (glThis->fogging != 0) {
991 glDisable(GL_FOG);
992 glThis->fogging = 0;
996 /* Handle the 'no-normal' case */
997 if ((vertex_lit == FALSE) && This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1]) {
998 if (glThis->lighting == 0) {
999 glEnable(GL_LIGHTING);
1000 glThis->lighting = 1;
1002 } else {
1003 if (glThis->lighting != 0) {
1004 glDisable(GL_LIGHTING);
1005 glThis->lighting = 0;
1009 /* Handle the code for pre-vertex material properties */
1010 if (vertex_transformed == FALSE) {
1011 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1012 This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1013 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1014 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1015 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1016 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1017 glEnable(GL_COLOR_MATERIAL);
1024 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1025 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1027 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1029 switch (d3dvt) {
1030 case D3DVT_VERTEX: {
1031 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1032 strided.position.dwStride = sizeof(D3DVERTEX);
1033 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1034 strided.normal.dwStride = sizeof(D3DVERTEX);
1035 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1036 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1037 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1038 } break;
1040 case D3DVT_LVERTEX: {
1041 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1042 strided.position.dwStride = sizeof(D3DLVERTEX);
1043 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1044 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1045 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1046 strided.specular.dwStride = sizeof(D3DLVERTEX);
1047 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1048 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1049 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1050 } break;
1052 case D3DVT_TLVERTEX: {
1053 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1054 strided.position.dwStride = sizeof(D3DTLVERTEX);
1055 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1056 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1057 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1058 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1059 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1060 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1061 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1062 } break;
1064 default:
1065 FIXME("Unhandled vertex type %08x\n", d3dvt);
1066 break;
1070 HRESULT WINAPI
1071 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1072 D3DPRIMITIVETYPE d3dptPrimitiveType,
1073 D3DVERTEXTYPE d3dvtVertexType,
1074 LPVOID lpvVertices,
1075 DWORD dwVertexCount,
1076 DWORD dwFlags)
1078 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1080 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1081 if (TRACE_ON(ddraw)) {
1082 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1085 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1087 return DD_OK;
1090 HRESULT WINAPI
1091 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1092 D3DPRIMITIVETYPE d3dptPrimitiveType,
1093 D3DVERTEXTYPE d3dvtVertexType,
1094 LPVOID lpvVertices,
1095 DWORD dwVertexCount,
1096 LPWORD dwIndices,
1097 DWORD dwIndexCount,
1098 DWORD dwFlags)
1100 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1101 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1102 if (TRACE_ON(ddraw)) {
1103 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1106 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1108 return DD_OK;
1111 HRESULT WINAPI
1112 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1113 LPD3DEXECUTEBUFFERDESC lpDesc,
1114 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1115 IUnknown* pUnkOuter)
1117 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1118 IDirect3DExecuteBufferImpl *ret;
1119 HRESULT ret_value;
1121 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1123 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1124 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1126 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1128 return ret_value;
1131 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1132 static BOOLEAN first = TRUE;
1133 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1134 unsigned int row;
1135 GLenum type;
1137 if (first) {
1138 MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1139 first = FALSE;
1142 TRACE("flushing ZBuffer back to GL\n");
1144 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1145 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1146 d3ddevice_set_ortho(d3d_dev);
1149 glMatrixMode(GL_MODELVIEW);
1150 glLoadIdentity();
1152 if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1153 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1154 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1156 /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1157 in some drivers...
1159 switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1160 case 16: type = GL_UNSIGNED_SHORT; break;
1161 case 32: type = GL_UNSIGNED_INT; break;
1162 default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1165 for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1166 /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1167 glRasterPos2i(0, row + 1);
1168 glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1169 ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1172 restore_state:
1173 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1174 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1175 glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1176 if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1179 /* These are the various handler used in the generic path */
1180 inline static void handle_xyz(D3DVALUE *coords) {
1181 glVertex3fv(coords);
1183 inline static void handle_xyzrhw(D3DVALUE *coords) {
1184 if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1185 glVertex3fv(coords);
1186 else {
1187 GLfloat w = 1.0 / coords[3];
1189 glVertex4f(coords[0] * w,
1190 coords[1] * w,
1191 coords[2] * w,
1195 inline static void handle_normal(D3DVALUE *coords) {
1196 glNormal3fv(coords);
1199 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1200 if (sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] ||
1201 sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1]) {
1202 glColor4ub((*color >> 16) & 0xFF,
1203 (*color >> 8) & 0xFF,
1204 (*color >> 0) & 0xFF,
1205 (*color >> 24) & 0xFF);
1206 } else {
1207 glColor3ub((*color >> 16) & 0xFF,
1208 (*color >> 8) & 0xFF,
1209 (*color >> 0) & 0xFF);
1213 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1214 glColor4ub((*color >> 16) & 0xFF,
1215 (*color >> 8) & 0xFF,
1216 (*color >> 0) & 0xFF,
1217 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1220 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1221 if ((lighted == FALSE) &&
1222 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1223 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1224 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1225 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1226 handle_diffuse_base(sb, color);
1228 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1229 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1230 handle_diffuse_base(sb, color);
1232 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1233 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1234 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1235 handle_diffuse_base(sb, color);
1237 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1238 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1239 handle_diffuse_base(sb, color);
1241 } else {
1242 handle_diffuse_base(sb, color);
1246 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1247 if ((lighted == FALSE) &&
1248 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1249 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1250 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1251 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1252 handle_specular_base(sb, color);
1254 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1255 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1256 handle_specular_base(sb, color);
1258 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1259 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1260 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1261 handle_specular_base(sb, color);
1263 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1264 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1265 handle_specular_base(sb, color);
1268 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1271 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1272 if (lighted) {
1273 DWORD color = *color_d;
1274 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
1275 /* Special case where the specular value is used to do fogging */
1276 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1277 color &= 0xFF000000; /* Only keep the alpha component */
1278 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1279 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1280 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1282 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1283 /* Standard specular value in transformed mode. TODO */
1285 handle_diffuse_base(sb, &color);
1286 } else {
1287 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1288 handle_diffuse(sb, color_d, FALSE);
1289 handle_specular(sb, color_s, FALSE);
1290 } else {
1291 /* In that case, only put the diffuse color... */
1292 handle_diffuse_base(sb, color_d);
1297 static void handle_texture(DWORD size, const D3DVALUE *coords) {
1298 switch (size) {
1299 case 1: glTexCoord1fv(coords); break;
1300 case 2: glTexCoord2fv(coords); break;
1301 case 3: glTexCoord3fv(coords); break;
1302 case 4: glTexCoord4fv(coords); break;
1306 inline static void handle_textures(DWORD size, const D3DVALUE *coords, int tex_stage) {
1307 if (GL_extensions.max_texture_units > 0) {
1308 GL_extensions.glMultiTexCoord[size - 1](GL_TEXTURE0_WINE + tex_stage, coords);
1309 } else {
1310 if (tex_stage == 0) handle_texture(size, coords);
1314 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1315 D3DPRIMITIVETYPE d3dptPrimitiveType,
1316 DWORD d3dvtVertexType,
1317 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1318 DWORD dwVertexCount,
1319 LPWORD dwIndices,
1320 DWORD dwIndexCount,
1321 DWORD dwFlags)
1323 BOOLEAN vertex_lighted = FALSE;
1324 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1325 int num_active_stages = 0;
1326 int num_tex_index = GET_TEXCOUNT_FROM_FVF(d3dvtVertexType);
1328 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1329 if (TRACE_ON(ddraw)) {
1330 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1333 /* This is to prevent 'thread contention' between a thread locking the device and another
1334 doing 3D display on it... */
1335 EnterCriticalSection(&(This->crit));
1337 ENTER_GL();
1338 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1339 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1341 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1343 if (This->current_zbuffer == NULL) {
1344 /* Search for an attached ZBuffer */
1345 static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1346 LPDIRECTDRAWSURFACE7 zbuf;
1347 HRESULT hr;
1349 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1350 (DDSCAPS2 *) &zbuf_caps, &zbuf);
1351 if (!FAILED(hr)) {
1352 This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1353 IDirectDrawSurface7_Release(zbuf);
1356 if (This->current_zbuffer != NULL) {
1357 if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1358 flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1362 if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1363 ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1364 vertex_lighted = TRUE;
1366 /* Compute the number of active texture stages and set the various texture parameters */
1367 num_active_stages = draw_primitive_handle_textures(This);
1369 /* And restore to handle '0' in the case we use glTexCoord calls */
1370 if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1371 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1372 glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1375 draw_primitive_handle_GL_state(This,
1376 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1377 vertex_lighted);
1379 /* First, see if we can use the OpenGL vertex arrays... This is very limited
1380 for now to some 'special' cases where we can do a direct mapping between D3D
1381 types and GL types.
1383 Note: in the future all calls will go through vertex arrays but the arrays
1384 will be generated by this function.
1386 Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1387 (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1388 which, as we are little indian, gives a B, G, R, A storage in memory.
1390 if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1391 ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1392 int tex_stage;
1393 TRACE(" using GL vertex arrays for performance !\n");
1394 /* First, the vertices (we are sure we have some :-) */
1395 glEnableClientState(GL_VERTEX_ARRAY);
1396 glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1397 /* Then the normals */
1398 if (d3dvtVertexType & D3DFVF_NORMAL) {
1399 glEnableClientState(GL_NORMAL_ARRAY);
1400 glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1402 /* Then the diffuse colour */
1403 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1404 glEnableClientState(GL_COLOR_ARRAY);
1405 glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1406 ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1408 /* Then the various textures */
1409 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1410 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1411 if (tex_index >= num_tex_index) {
1412 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1413 tex_index = num_tex_index - 1;
1415 if (GL_extensions.glClientActiveTexture) {
1416 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1418 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1419 glTexCoordPointer(GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index), GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1420 lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1422 if (dwIndices != NULL) {
1423 glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1424 } else {
1425 glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1427 glDisableClientState(GL_VERTEX_ARRAY);
1428 if (d3dvtVertexType & D3DFVF_NORMAL) {
1429 glDisableClientState(GL_NORMAL_ARRAY);
1431 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1432 glDisableClientState(GL_COLOR_ARRAY);
1434 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1435 if (GL_extensions.glClientActiveTexture) {
1436 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1438 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1440 } else {
1441 glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1443 /* Some fast paths first before the generic case.... */
1444 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1445 unsigned int index;
1447 for (index = 0; index < dwIndexCount; index++) {
1448 int i = (dwIndices == NULL) ? index : dwIndices[index];
1449 D3DVALUE *normal =
1450 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1451 D3DVALUE *tex_coord =
1452 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1453 D3DVALUE *position =
1454 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1456 handle_normal(normal);
1457 handle_texture(2, tex_coord);
1458 handle_xyz(position);
1460 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1461 position[0], position[1], position[2],
1462 normal[0], normal[1], normal[2],
1463 tex_coord[0], tex_coord[1]);
1465 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1466 unsigned int index;
1468 for (index = 0; index < dwIndexCount; index++) {
1469 int i = (dwIndices == NULL) ? index : dwIndices[index];
1470 DWORD *color_d =
1471 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1472 DWORD *color_s =
1473 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1474 D3DVALUE *tex_coord =
1475 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1476 D3DVALUE *position =
1477 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1479 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1480 handle_texture(2, tex_coord);
1481 handle_xyzrhw(position);
1483 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1484 position[0], position[1], position[2], position[3],
1485 (*color_d >> 16) & 0xFF,
1486 (*color_d >> 8) & 0xFF,
1487 (*color_d >> 0) & 0xFF,
1488 (*color_d >> 24) & 0xFF,
1489 (*color_s >> 16) & 0xFF,
1490 (*color_s >> 8) & 0xFF,
1491 (*color_s >> 0) & 0xFF,
1492 (*color_s >> 24) & 0xFF,
1493 tex_coord[0], tex_coord[1]);
1495 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1496 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1497 /* This is the 'slow path' but that should support all possible vertex formats out there...
1498 Note that people should write a fast path for all vertex formats out there...
1500 unsigned int index;
1501 /* static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 }; */
1503 for (index = 0; index < dwIndexCount; index++) {
1504 int i = (dwIndices == NULL) ? index : dwIndices[index];
1505 int tex_stage;
1507 if (d3dvtVertexType & D3DFVF_NORMAL) {
1508 D3DVALUE *normal =
1509 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1510 handle_normal(normal);
1512 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1513 DWORD *color_d =
1514 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1515 DWORD *color_s =
1516 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1517 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1518 } else {
1519 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1520 DWORD *color_s =
1521 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1522 handle_specular(&(This->state_block), color_s, vertex_lighted);
1523 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1524 DWORD *color_d =
1525 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1526 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1530 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1531 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1532 D3DVALUE *tex_coord;
1534 if (tex_index >= num_tex_index) {
1535 /* This will have to be checked on Windows. RealMYST uses this feature and I would find it more
1536 * logical to re-use the index of the previous stage than a default index of '0'.
1539 /* handle_textures((const D3DVALUE *) no_index, tex_stage); */
1540 tex_index = num_tex_index - 1;
1542 tex_coord = (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1543 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1544 handle_textures(GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index), tex_coord, tex_stage);
1547 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1548 D3DVALUE *position =
1549 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1550 handle_xyz(position);
1551 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1552 D3DVALUE *position =
1553 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1554 handle_xyzrhw(position);
1557 if (TRACE_ON(ddraw_geom)) {
1558 unsigned int tex_index;
1560 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1561 D3DVALUE *position =
1562 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1563 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1564 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1565 D3DVALUE *position =
1566 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1567 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1569 if (d3dvtVertexType & D3DFVF_NORMAL) {
1570 D3DVALUE *normal =
1571 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1572 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1574 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1575 DWORD *color_d =
1576 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1577 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1578 (*color_d >> 16) & 0xFF,
1579 (*color_d >> 8) & 0xFF,
1580 (*color_d >> 0) & 0xFF,
1581 (*color_d >> 24) & 0xFF);
1583 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1584 DWORD *color_s =
1585 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1586 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1587 (*color_s >> 16) & 0xFF,
1588 (*color_s >> 8) & 0xFF,
1589 (*color_s >> 0) & 0xFF,
1590 (*color_s >> 24) & 0xFF);
1592 for (tex_index = 0; tex_index < GET_TEXCOUNT_FROM_FVF(d3dvtVertexType); tex_index++) {
1593 D3DVALUE *tex_coord =
1594 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1595 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1596 switch (GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index)) {
1597 case 1: TRACE_(ddraw_geom)(" / %f", tex_coord[0]); break;
1598 case 2: TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]); break;
1599 case 3: TRACE_(ddraw_geom)(" / %f %f %f", tex_coord[0], tex_coord[1], tex_coord[2]); break;
1600 case 4: TRACE_(ddraw_geom)(" / %f %f %f %f", tex_coord[0], tex_coord[1], tex_coord[2], tex_coord[3]); break;
1601 default: TRACE_(ddraw_geom)("Invalid texture size (%ld) !!!", GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index)); break;
1604 TRACE_(ddraw_geom)("\n");
1607 } else {
1608 ERR(" matrix weighting not handled yet....\n");
1611 glEnd();
1614 /* Whatever the case, disable the color material stuff */
1615 glDisable(GL_COLOR_MATERIAL);
1617 LEAVE_GL();
1618 TRACE("End\n");
1620 LeaveCriticalSection(&(This->crit));
1623 HRESULT WINAPI
1624 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1625 D3DPRIMITIVETYPE d3dptPrimitiveType,
1626 DWORD d3dvtVertexType,
1627 LPVOID lpvVertices,
1628 DWORD dwVertexCount,
1629 DWORD dwFlags)
1631 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1632 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1634 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1635 if (TRACE_ON(ddraw)) {
1636 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1639 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1640 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1642 return DD_OK;
1645 HRESULT WINAPI
1646 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1647 D3DPRIMITIVETYPE d3dptPrimitiveType,
1648 DWORD d3dvtVertexType,
1649 LPVOID lpvVertices,
1650 DWORD dwVertexCount,
1651 LPWORD dwIndices,
1652 DWORD dwIndexCount,
1653 DWORD dwFlags)
1655 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1656 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1658 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1659 if (TRACE_ON(ddraw)) {
1660 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1663 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1664 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1666 return DD_OK;
1669 HRESULT WINAPI
1670 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1671 D3DPRIMITIVETYPE d3dptPrimitiveType,
1672 DWORD dwVertexType,
1673 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1674 DWORD dwVertexCount,
1675 DWORD dwFlags)
1677 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1679 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1680 if (TRACE_ON(ddraw)) {
1681 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1683 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1685 return DD_OK;
1688 HRESULT WINAPI
1689 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1690 D3DPRIMITIVETYPE d3dptPrimitiveType,
1691 DWORD dwVertexType,
1692 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1693 DWORD dwVertexCount,
1694 LPWORD lpIndex,
1695 DWORD dwIndexCount,
1696 DWORD dwFlags)
1698 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1700 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1701 if (TRACE_ON(ddraw)) {
1702 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1705 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1707 return DD_OK;
1710 HRESULT WINAPI
1711 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1712 D3DPRIMITIVETYPE d3dptPrimitiveType,
1713 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1714 DWORD dwStartVertex,
1715 DWORD dwNumVertices,
1716 DWORD dwFlags)
1718 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1719 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1720 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1722 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1723 if (TRACE_ON(ddraw)) {
1724 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1727 if (vb_impl->processed) {
1728 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1729 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1731 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1732 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1733 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1735 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1736 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1738 } else {
1739 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1740 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1743 return DD_OK;
1746 HRESULT WINAPI
1747 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1748 D3DPRIMITIVETYPE d3dptPrimitiveType,
1749 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1750 DWORD dwStartVertex,
1751 DWORD dwNumVertices,
1752 LPWORD lpwIndices,
1753 DWORD dwIndexCount,
1754 DWORD dwFlags)
1756 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1757 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1758 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1760 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1761 if (TRACE_ON(ddraw)) {
1762 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1765 if (vb_impl->processed) {
1766 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1767 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1769 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1770 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1771 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1773 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1774 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1776 } else {
1777 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1778 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1781 return DD_OK;
1784 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1785 static BOOLEAN
1786 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1788 BOOLEAN is_complement = FALSE;
1789 BOOLEAN is_alpha_replicate = FALSE;
1790 BOOLEAN handled = TRUE;
1791 GLenum src;
1792 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1793 int num;
1795 if (is_color) {
1796 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1797 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1798 else {
1799 handled = FALSE;
1800 num = 0;
1802 if (tex_op == D3DTOP_SELECTARG2) {
1803 num = 1 - num;
1805 } else {
1806 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1807 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1808 else {
1809 handled = FALSE;
1810 num = 0;
1812 if (tex_op == D3DTOP_SELECTARG2) {
1813 num = 1 - num;
1817 if (dwState & D3DTA_COMPLEMENT) {
1818 is_complement = TRUE;
1820 if (dwState & D3DTA_ALPHAREPLICATE) {
1821 is_alpha_replicate = TRUE;
1823 dwState &= D3DTA_SELECTMASK;
1824 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1825 dwState = D3DTA_DIFFUSE;
1828 switch (dwState) {
1829 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1830 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1831 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1832 case D3DTA_TFACTOR: {
1833 /* Get the constant value from the current rendering state */
1834 GLfloat color[4];
1835 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1837 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1838 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1839 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1840 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1841 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1843 src = GL_CONSTANT_EXT;
1844 } break;
1845 default: src = GL_TEXTURE; handled = FALSE; break;
1848 if (is_color) {
1849 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1850 if (is_alpha_replicate) {
1851 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1852 } else {
1853 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1855 } else {
1856 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1857 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1860 return handled;
1863 HRESULT WINAPI
1864 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1865 DWORD dwStage,
1866 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1867 DWORD dwState)
1869 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1870 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1871 const char *type;
1872 DWORD prev_state;
1873 GLenum unit;
1875 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1877 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1878 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1879 return DD_OK;
1882 unit = GL_TEXTURE0_WINE + dwStage;
1883 if (unit != glThis->current_active_tex_unit) {
1884 GL_extensions.glActiveTexture(unit);
1885 glThis->current_active_tex_unit = unit;
1888 switch (d3dTexStageStateType) {
1889 #define GEN_CASE(a) case a: type = #a; break
1890 GEN_CASE(D3DTSS_COLOROP);
1891 GEN_CASE(D3DTSS_COLORARG1);
1892 GEN_CASE(D3DTSS_COLORARG2);
1893 GEN_CASE(D3DTSS_ALPHAOP);
1894 GEN_CASE(D3DTSS_ALPHAARG1);
1895 GEN_CASE(D3DTSS_ALPHAARG2);
1896 GEN_CASE(D3DTSS_BUMPENVMAT00);
1897 GEN_CASE(D3DTSS_BUMPENVMAT01);
1898 GEN_CASE(D3DTSS_BUMPENVMAT10);
1899 GEN_CASE(D3DTSS_BUMPENVMAT11);
1900 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1901 GEN_CASE(D3DTSS_ADDRESS);
1902 GEN_CASE(D3DTSS_ADDRESSU);
1903 GEN_CASE(D3DTSS_ADDRESSV);
1904 GEN_CASE(D3DTSS_BORDERCOLOR);
1905 GEN_CASE(D3DTSS_MAGFILTER);
1906 GEN_CASE(D3DTSS_MINFILTER);
1907 GEN_CASE(D3DTSS_MIPFILTER);
1908 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1909 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1910 GEN_CASE(D3DTSS_MAXANISOTROPY);
1911 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1912 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1913 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1914 #undef GEN_CASE
1915 default: type = "UNKNOWN";
1918 /* Store the values in the state array */
1919 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1920 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1921 /* Some special cases when one state modifies more than one... */
1922 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1923 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1924 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1927 ENTER_GL();
1929 switch (d3dTexStageStateType) {
1930 case D3DTSS_MINFILTER:
1931 case D3DTSS_MIPFILTER:
1932 if (TRACE_ON(ddraw)) {
1933 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1934 switch ((D3DTEXTUREMINFILTER) dwState) {
1935 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1936 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1937 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1939 } else {
1940 switch ((D3DTEXTUREMIPFILTER) dwState) {
1941 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1942 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1943 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1944 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1948 break;
1950 case D3DTSS_MAGFILTER:
1951 if (TRACE_ON(ddraw)) {
1952 switch ((D3DTEXTUREMAGFILTER) dwState) {
1953 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1954 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1955 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1958 break;
1960 case D3DTSS_ADDRESS:
1961 case D3DTSS_ADDRESSU:
1962 case D3DTSS_ADDRESSV: {
1963 switch ((D3DTEXTUREADDRESS) dwState) {
1964 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1965 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1966 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1967 case D3DTADDRESS_MIRROR:
1968 if (GL_extensions.mirrored_repeat) {
1969 TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1970 } else {
1971 FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1973 break;
1974 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1976 } break;
1978 case D3DTSS_ALPHAOP:
1979 case D3DTSS_COLOROP: {
1980 int scale = 1;
1981 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1982 const char *value;
1983 int handled = 1;
1985 switch (dwState) {
1986 #define GEN_CASE(a) case a: value = #a; break
1987 GEN_CASE(D3DTOP_DISABLE);
1988 GEN_CASE(D3DTOP_SELECTARG1);
1989 GEN_CASE(D3DTOP_SELECTARG2);
1990 GEN_CASE(D3DTOP_MODULATE);
1991 GEN_CASE(D3DTOP_MODULATE2X);
1992 GEN_CASE(D3DTOP_MODULATE4X);
1993 GEN_CASE(D3DTOP_ADD);
1994 GEN_CASE(D3DTOP_ADDSIGNED);
1995 GEN_CASE(D3DTOP_ADDSIGNED2X);
1996 GEN_CASE(D3DTOP_SUBTRACT);
1997 GEN_CASE(D3DTOP_ADDSMOOTH);
1998 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1999 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
2000 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
2001 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
2002 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
2003 GEN_CASE(D3DTOP_PREMODULATE);
2004 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
2005 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
2006 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
2007 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
2008 GEN_CASE(D3DTOP_BUMPENVMAP);
2009 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
2010 GEN_CASE(D3DTOP_DOTPRODUCT3);
2011 GEN_CASE(D3DTOP_FORCE_DWORD);
2012 #undef GEN_CASE
2013 default: value = "UNKNOWN";
2016 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
2017 glDisable(GL_TEXTURE_2D);
2018 TRACE(" disabling 2D texturing.\n");
2019 } else {
2020 /* Re-enable texturing only if COLOROP was not already disabled... */
2021 if ((glThis->current_bound_texture[dwStage] != NULL) &&
2022 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2023 glEnable(GL_TEXTURE_2D);
2024 TRACE(" enabling 2D texturing.\n");
2027 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2028 if ((dwState != D3DTOP_DISABLE) &&
2029 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2030 if (glThis->current_tex_env != GL_COMBINE_EXT) {
2031 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2032 glThis->current_tex_env = GL_COMBINE_EXT;
2036 /* Now set up the operand correctly */
2037 switch (dwState) {
2038 case D3DTOP_DISABLE:
2039 /* Contrary to the docs, alpha can be disabled when colorop is enabled
2040 and it works, so ignore this op */
2041 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2042 break;
2044 case D3DTOP_SELECTARG1:
2045 case D3DTOP_SELECTARG2:
2046 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2047 break;
2049 case D3DTOP_MODULATE4X:
2050 scale = scale * 2; /* Drop through */
2051 case D3DTOP_MODULATE2X:
2052 scale = scale * 2; /* Drop through */
2053 case D3DTOP_MODULATE:
2054 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2055 break;
2057 case D3DTOP_ADD:
2058 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2059 break;
2061 case D3DTOP_ADDSIGNED2X:
2062 scale = scale * 2; /* Drop through */
2063 case D3DTOP_ADDSIGNED:
2064 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2065 break;
2067 /* For the four blending modes, use the Arg2 parameter */
2068 case D3DTOP_BLENDDIFFUSEALPHA:
2069 case D3DTOP_BLENDTEXTUREALPHA:
2070 case D3DTOP_BLENDFACTORALPHA:
2071 case D3DTOP_BLENDCURRENTALPHA: {
2072 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2074 switch (dwState) {
2075 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2076 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2077 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
2078 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2081 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2082 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2083 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2084 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2085 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2086 } break;
2088 default:
2089 handled = FALSE;
2090 break;
2094 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2095 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2096 /* Switch the arguments if needed... */
2097 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2098 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2099 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2100 dwState);
2101 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2102 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2103 dwState);
2104 } else {
2105 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2106 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2107 dwState);
2108 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2109 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2110 dwState);
2114 if (handled) {
2115 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2116 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2117 } else {
2118 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2120 TRACE(" Stage type is : %s => %s\n", type, value);
2121 } else {
2122 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2124 } break;
2126 case D3DTSS_COLORARG1:
2127 case D3DTSS_COLORARG2:
2128 case D3DTSS_ALPHAARG1:
2129 case D3DTSS_ALPHAARG2: {
2130 const char *value, *value_comp = "", *value_alpha = "";
2131 BOOLEAN handled;
2132 D3DTEXTUREOP tex_op;
2134 switch (dwState & D3DTA_SELECTMASK) {
2135 #define GEN_CASE(a) case a: value = #a; break
2136 GEN_CASE(D3DTA_DIFFUSE);
2137 GEN_CASE(D3DTA_CURRENT);
2138 GEN_CASE(D3DTA_TEXTURE);
2139 GEN_CASE(D3DTA_TFACTOR);
2140 GEN_CASE(D3DTA_SPECULAR);
2141 #undef GEN_CASE
2142 default: value = "UNKNOWN";
2144 if (dwState & D3DTA_COMPLEMENT) {
2145 value_comp = " | D3DTA_COMPLEMENT";
2147 if (dwState & D3DTA_ALPHAREPLICATE) {
2148 value_alpha = " | D3DTA_ALPHAREPLICATE";
2151 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2152 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2153 } else {
2154 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2157 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2159 if (handled) {
2160 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2161 } else {
2162 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2164 } break;
2166 case D3DTSS_MIPMAPLODBIAS: {
2167 D3DVALUE value = *((D3DVALUE *) &dwState);
2168 BOOLEAN handled = TRUE;
2170 if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2171 handled = FALSE;
2173 if (handled) {
2174 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2175 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2176 } else {
2177 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2179 } break;
2181 case D3DTSS_MAXMIPLEVEL:
2182 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2183 break;
2185 case D3DTSS_BORDERCOLOR:
2186 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2187 ((dwState >> 16) & 0xFF),
2188 ((dwState >> 8) & 0xFF),
2189 ((dwState >> 0) & 0xFF),
2190 ((dwState >> 24) & 0xFF));
2191 break;
2193 case D3DTSS_TEXCOORDINDEX: {
2194 BOOLEAN handled = TRUE;
2195 const char *value;
2197 switch (dwState & 0xFFFF0000) {
2198 #define GEN_CASE(a) case a: value = #a; break
2199 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2200 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2201 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2202 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2203 #undef GEN_CASE
2204 default: value = "UNKNOWN";
2206 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2207 handled = FALSE;
2209 if (handled) {
2210 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2211 } else {
2212 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2214 } break;
2216 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2217 const char *projected = "", *value;
2218 BOOLEAN handled = TRUE;
2219 switch (dwState & 0xFF) {
2220 #define GEN_CASE(a) case a: value = #a; break
2221 GEN_CASE(D3DTTFF_DISABLE);
2222 GEN_CASE(D3DTTFF_COUNT1);
2223 GEN_CASE(D3DTTFF_COUNT2);
2224 GEN_CASE(D3DTTFF_COUNT3);
2225 GEN_CASE(D3DTTFF_COUNT4);
2226 #undef GEN_CASE
2227 default: value = "UNKNOWN";
2229 if (dwState & D3DTTFF_PROJECTED) {
2230 projected = " | D3DTTFF_PROJECTED";
2231 handled = FALSE;
2234 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2235 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2238 if (handled) {
2239 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2240 } else {
2241 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2243 } break;
2245 default:
2246 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2247 break;
2250 LEAVE_GL();
2252 return DD_OK;
2255 static DWORD
2256 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2258 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2259 DWORD stage;
2260 BOOLEAN enable_colorkey = FALSE;
2262 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2263 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2264 GLenum unit;
2266 /* If this stage is disabled, no need to go further... */
2267 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2268 break;
2270 /* First check if we need to bind any other texture for this stage */
2271 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2272 if (This->current_texture[stage] == NULL) {
2273 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2275 unit = GL_TEXTURE0_WINE + stage;
2276 if (unit != glThis->current_active_tex_unit) {
2277 GL_extensions.glActiveTexture(unit);
2278 glThis->current_active_tex_unit = unit;
2280 glBindTexture(GL_TEXTURE_2D, 0);
2281 glDisable(GL_TEXTURE_2D);
2282 } else {
2283 GLenum tex_name = gltex_get_tex_name(surf_ptr);
2285 unit = GL_TEXTURE0_WINE + stage;
2286 if (unit != glThis->current_active_tex_unit) {
2287 GL_extensions.glActiveTexture(unit);
2288 glThis->current_active_tex_unit = unit;
2291 if (glThis->current_bound_texture[stage] == NULL) {
2292 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2293 TRACE(" enabling 2D texturing and");
2294 glEnable(GL_TEXTURE_2D);
2297 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2298 glBindTexture(GL_TEXTURE_2D, tex_name);
2301 glThis->current_bound_texture[stage] = This->current_texture[stage];
2302 } else {
2303 if (glThis->current_bound_texture[stage] == NULL) {
2304 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2305 } else {
2306 TRACE(" using already bound texture id %d for stage %ld.\n",
2307 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2311 /* If no texure valid for this stage, go out of the loop */
2312 if (This->current_texture[stage] == NULL) break;
2314 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2315 This will also update the various texture parameters if needed.
2317 gltex_upload_texture(surf_ptr, This, stage);
2319 /* And finally check for color-keying (only on first stage) */
2320 if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2321 if (stage == 0) {
2322 enable_colorkey = TRUE;
2323 } else {
2324 static BOOL warn = FALSE;
2325 if (warn == FALSE) {
2326 warn = TRUE;
2327 WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2330 } else {
2331 if (stage == 0) {
2332 enable_colorkey = FALSE;
2337 /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2338 if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2339 (glThis->parent.version == 1)) &&
2340 (enable_colorkey)) {
2341 TRACE(" colorkey activated.\n");
2343 if (glThis->alpha_test == FALSE) {
2344 glEnable(GL_ALPHA_TEST);
2345 glThis->alpha_test = TRUE;
2347 if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2348 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1]) {
2349 static BOOL warn = FALSE;
2350 if (warn == FALSE) {
2351 warn = TRUE;
2352 WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2355 glThis->current_alpha_test_func = GL_NOTEQUAL;
2356 glThis->current_alpha_test_ref = 0.0;
2357 glAlphaFunc(GL_NOTEQUAL, 0.0);
2359 /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2360 Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2361 } else {
2362 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2363 glDisable(GL_ALPHA_TEST);
2364 glThis->alpha_test = FALSE;
2366 /* Maybe we should restore here the application-given alpha test states ? */
2369 return stage;
2372 HRESULT WINAPI
2373 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2374 DWORD dwStage,
2375 LPDIRECTDRAWSURFACE7 lpTexture2)
2377 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2379 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2381 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2382 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2383 if (lpTexture2 != NULL) {
2384 WARN(" setting a texture to a non-supported texture stage !\n");
2386 return DD_OK;
2389 if (This->current_texture[dwStage] != NULL) {
2390 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2393 if (lpTexture2 == NULL) {
2394 This->current_texture[dwStage] = NULL;
2395 } else {
2396 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2397 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2398 This->current_texture[dwStage] = tex_impl;
2401 return DD_OK;
2404 static HRESULT WINAPI
2405 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2406 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2408 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2409 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2411 fill_opengl_caps_7(lpD3DHELDevDesc);
2413 TRACE(" returning caps : no dump function yet.\n");
2415 return DD_OK;
2418 HRESULT WINAPI
2419 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2420 LPD3DMATERIAL7 lpMat)
2422 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2423 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2425 if (TRACE_ON(ddraw)) {
2426 TRACE(" material is : \n");
2427 dump_D3DMATERIAL7(lpMat);
2430 This->current_material = *lpMat;
2432 ENTER_GL();
2433 glMaterialfv(GL_FRONT_AND_BACK,
2434 GL_DIFFUSE,
2435 (float *) &(This->current_material.u.diffuse));
2436 glMaterialfv(GL_FRONT_AND_BACK,
2437 GL_AMBIENT,
2438 (float *) &(This->current_material.u1.ambient));
2439 glMaterialfv(GL_FRONT_AND_BACK,
2440 GL_SPECULAR,
2441 (float *) &(This->current_material.u2.specular));
2442 glMaterialfv(GL_FRONT_AND_BACK,
2443 GL_EMISSION,
2444 (float *) &(This->current_material.u3.emissive));
2445 glMaterialf(GL_FRONT_AND_BACK,
2446 GL_SHININESS,
2447 This->current_material.u4.power); /* Not sure about this... */
2448 LEAVE_GL();
2450 return DD_OK;
2453 static LPD3DLIGHT7 get_light(IDirect3DDeviceImpl *This, DWORD dwLightIndex)
2455 if (dwLightIndex >= This->num_set_lights)
2457 /* Extend, or allocate the light parameters array. */
2458 DWORD newlightnum = dwLightIndex + 1;
2459 LPD3DLIGHT7 newarrayptr = NULL;
2461 if (This->light_parameters)
2462 newarrayptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2463 This->light_parameters, newlightnum * sizeof(D3DLIGHT7));
2464 else
2465 newarrayptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2466 newlightnum * sizeof(D3DLIGHT7));
2468 if (!newarrayptr)
2469 return NULL;
2471 This->light_parameters = newarrayptr;
2472 This->num_set_lights = newlightnum;
2475 return &This->light_parameters[dwLightIndex];
2478 HRESULT WINAPI
2479 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2480 DWORD dwLightIndex,
2481 LPD3DLIGHT7 lpLight)
2483 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2484 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2485 LPD3DLIGHT7 lpdestlight = get_light( This, dwLightIndex );
2487 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2489 if (TRACE_ON(ddraw)) {
2490 TRACE(" setting light : \n");
2491 dump_D3DLIGHT7(lpLight);
2494 /* DirectX7 documentation states that this function can return
2495 DDERR_OUTOFMEMORY, so we do just that in case of an allocation
2496 error (which is the only reason why get_light() can fail). */
2497 if( !lpdestlight )
2498 return DDERR_OUTOFMEMORY;
2500 *lpdestlight = *lpLight;
2502 /* Some checks to print out nice warnings :-) */
2503 switch (lpLight->dltType) {
2504 case D3DLIGHT_DIRECTIONAL:
2505 case D3DLIGHT_POINT:
2506 /* These are handled properly... */
2507 break;
2509 case D3DLIGHT_SPOT:
2510 if ((lpLight->dvTheta != 0.0) ||
2511 (lpLight->dvTheta != lpLight->dvPhi)) {
2512 ERR("dvTheta not fully supported yet !\n");
2514 break;
2516 default:
2517 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2520 /* This will force the Light setting on next drawing of primitives */
2521 glThis->transform_state = GL_TRANSFORM_NONE;
2523 return DD_OK;
2526 HRESULT WINAPI
2527 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2528 DWORD dwLightIndex,
2529 BOOL bEnable)
2531 int lightslot = -1, i;
2532 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2533 LPD3DLIGHT7 lpdestlight = get_light(This, dwLightIndex);
2535 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2537 /* The DirectX doc isn't as explicit as for SetLight as whether we can
2538 return this from this function, but it doesn't state otherwise. */
2539 if (!lpdestlight)
2540 return DDERR_OUTOFMEMORY;
2542 /* If this light hasn't been set, initialise it with default values. */
2543 if (lpdestlight->dltType == 0)
2545 TRACE("setting default light parameters\n");
2547 /* We always use HEAP_ZERO_MEMORY when allocating the light_parameters
2548 array, so we only have to setup anything that shoud not be zero. */
2549 lpdestlight->dltType = D3DLIGHT_DIRECTIONAL;
2550 lpdestlight->dcvDiffuse.u1.r = 1.f;
2551 lpdestlight->dcvDiffuse.u2.g = 1.f;
2552 lpdestlight->dcvDiffuse.u3.b = 1.f;
2553 lpdestlight->dvDirection.u3.z = 1.f;
2556 /* Look for this light in the active lights array. */
2557 for (i = 0; i < This->max_active_lights; i++)
2558 if (This->active_lights[i] == dwLightIndex)
2560 lightslot = i;
2561 break;
2564 /* If we didn't find it, let's find the first available slot, if any. */
2565 if (lightslot == -1)
2566 for (i = 0; i < This->max_active_lights; i++)
2567 if (This->active_lights[i] == ~0)
2569 lightslot = i;
2570 break;
2573 ENTER_GL();
2574 if (bEnable) {
2575 if (lightslot == -1)
2577 /* This means that the app is trying to enable more lights than
2578 the maximum possible indicated in the caps.
2580 Windows actually let you do this, and disable one of the
2581 previously enabled lights to let you enable this one.
2583 It's not documented and I'm not sure how windows pick which light
2584 to disable to make room for this one. */
2585 FIXME("Enabling more light than the maximum is not supported yet.");
2586 return D3D_OK;
2589 glEnable(GL_LIGHT0 + lightslot);
2592 if (This->active_lights[lightslot] == ~0)
2594 /* This light gets active... Need to update its parameters to GL before the next drawing */
2595 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2597 This->active_lights[lightslot] = dwLightIndex;
2598 glThis->transform_state = GL_TRANSFORM_NONE;
2600 } else {
2601 glDisable(GL_LIGHT0 + lightslot);
2602 This->active_lights[lightslot] = ~0;
2605 LEAVE_GL();
2606 return DD_OK;
2609 HRESULT WINAPI
2610 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2612 IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2613 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2615 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2617 if (dwIndex >= This->max_clipping_planes) {
2618 return DDERR_INVALIDPARAMS;
2621 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2623 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2625 /* This is to force the reset of the transformation matrices on the next drawing.
2626 * This is needed to use the correct matrices for the various clipping planes.
2628 glThis->transform_state = GL_TRANSFORM_NONE;
2630 return D3D_OK;
2633 static HRESULT WINAPI
2634 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2635 LPD3DVIEWPORT7 lpData)
2637 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2638 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2640 if (TRACE_ON(ddraw)) {
2641 TRACE(" viewport is : \n");
2642 TRACE(" - dwX = %ld dwY = %ld\n",
2643 lpData->dwX, lpData->dwY);
2644 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2645 lpData->dwWidth, lpData->dwHeight);
2646 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2647 lpData->dvMinZ, lpData->dvMaxZ);
2649 ENTER_GL();
2651 /* Set the viewport */
2652 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2653 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2654 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2656 if ((lpData->dwX != This->active_viewport.dwX) ||
2657 (lpData->dwY != This->active_viewport.dwY) ||
2658 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2659 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2660 glViewport(lpData->dwX,
2661 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2662 lpData->dwWidth, lpData->dwHeight);
2665 LEAVE_GL();
2667 This->active_viewport = *lpData;
2669 return DD_OK;
2672 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2673 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2674 #else
2675 # define XCAST(fun) (void*)
2676 #endif
2678 static const IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2680 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2681 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2682 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2683 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2684 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2685 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2686 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2687 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2688 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2689 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2690 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2691 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2692 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2693 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2694 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2695 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2696 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2697 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2698 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2699 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2700 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2701 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2702 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2703 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2704 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2705 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2706 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2707 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2708 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2709 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2710 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2711 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2712 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2713 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2714 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2715 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2716 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2717 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2718 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2719 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2720 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2721 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2722 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2723 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2724 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2725 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2726 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2727 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2728 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2731 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2732 #undef XCAST
2733 #endif
2736 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2737 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2738 #else
2739 # define XCAST(fun) (void*)
2740 #endif
2742 static const IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2744 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2745 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2746 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2747 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2748 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2749 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2750 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2751 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2752 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2753 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2754 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2755 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2756 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2757 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2758 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2759 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2760 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2761 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2762 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2763 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2764 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2765 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2766 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2767 XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2768 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2769 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2770 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2771 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2772 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2773 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2774 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2775 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2776 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2777 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2778 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2779 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2780 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2781 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2782 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2783 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2784 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2785 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2788 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2789 #undef XCAST
2790 #endif
2793 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2794 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2795 #else
2796 # define XCAST(fun) (void*)
2797 #endif
2799 static const IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2801 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2802 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2803 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2804 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2805 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2806 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2807 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2808 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2809 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2810 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2811 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2812 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2813 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2814 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2815 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2816 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2817 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2818 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2819 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2820 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2821 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2822 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2823 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2824 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2825 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2826 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2827 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2828 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2829 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2830 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2831 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2832 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2833 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2836 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2837 #undef XCAST
2838 #endif
2841 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2842 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2843 #else
2844 # define XCAST(fun) (void*)
2845 #endif
2847 static const IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2849 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2850 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2851 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2852 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2853 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2854 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2855 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2856 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2857 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2858 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2859 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2860 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2861 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2862 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2863 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2864 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2865 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2866 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2867 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2868 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2869 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2870 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2873 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2874 #undef XCAST
2875 #endif
2877 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2878 WINE_GL_BUFFER_TYPE buffer_type,
2879 DWORD dwCount,
2880 LPD3DRECT lpRects,
2881 DWORD dwFlags,
2882 DWORD dwColor,
2883 D3DVALUE dvZ,
2884 DWORD dwStencil)
2886 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2887 GLbitfield bitfield = 0;
2888 D3DRECT rect;
2889 unsigned int i;
2891 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2892 if (TRACE_ON(ddraw)) {
2893 if (dwCount > 0) {
2894 unsigned int i;
2895 TRACE(" rectangles : \n");
2896 for (i = 0; i < dwCount; i++) {
2897 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2902 if (dwCount == 0) {
2903 dwCount = 1;
2904 rect.u1.x1 = 0;
2905 rect.u2.y1 = 0;
2906 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2907 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2908 lpRects = &rect;
2911 /* Clears the screen */
2912 ENTER_GL();
2914 if (dwFlags & D3DCLEAR_TARGET) {
2915 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2916 /* TODO: optimize here the case where Clear changes all the screen... */
2917 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2919 glThis->state[buffer_type] = SURFACE_GL;
2922 if (dwFlags & D3DCLEAR_ZBUFFER) {
2923 bitfield |= GL_DEPTH_BUFFER_BIT;
2924 if (glThis->depth_mask == FALSE) {
2925 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2927 if (dvZ != glThis->prev_clear_Z) {
2928 glClearDepth(dvZ);
2929 glThis->prev_clear_Z = dvZ;
2931 TRACE(" depth value : %f\n", dvZ);
2933 if (dwFlags & D3DCLEAR_STENCIL) {
2934 bitfield |= GL_STENCIL_BUFFER_BIT;
2935 if (dwStencil != glThis->prev_clear_stencil) {
2936 glClearStencil(dwStencil);
2937 glThis->prev_clear_stencil = dwStencil;
2939 TRACE(" stencil value : %ld\n", dwStencil);
2941 if (dwFlags & D3DCLEAR_TARGET) {
2942 bitfield |= GL_COLOR_BUFFER_BIT;
2943 if (dwColor != glThis->prev_clear_color) {
2944 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2945 ((dwColor >> 8) & 0xFF) / 255.0,
2946 ((dwColor >> 0) & 0xFF) / 255.0,
2947 ((dwColor >> 24) & 0xFF) / 255.0);
2948 glThis->prev_clear_color = dwColor;
2950 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2953 glEnable(GL_SCISSOR_TEST);
2954 for (i = 0; i < dwCount; i++) {
2955 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2956 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2957 glClear(bitfield);
2959 glDisable(GL_SCISSOR_TEST);
2961 if (dwFlags & D3DCLEAR_ZBUFFER) {
2962 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2965 LEAVE_GL();
2967 return DD_OK;
2970 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2971 DWORD dwCount,
2972 LPD3DRECT lpRects,
2973 DWORD dwFlags,
2974 DWORD dwColor,
2975 D3DVALUE dvZ,
2976 DWORD dwStencil)
2978 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2981 static HRESULT
2982 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2983 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2985 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2986 WINE_GL_BUFFER_TYPE buffer_type;
2988 /* First check if we BLT to the backbuffer... */
2989 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2990 buffer_type = WINE_GL_BUFFER_BACK;
2991 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2992 buffer_type = WINE_GL_BUFFER_FRONT;
2993 } else {
2994 ERR("Only BLT override to front or back-buffer is supported for now !\n");
2995 return DDERR_INVALIDPARAMS;
2998 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
2999 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
3000 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
3001 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
3002 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3003 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
3004 * GL to do it.
3006 return DDERR_INVALIDPARAMS;
3008 *buffer_type_p = buffer_type;
3010 return DD_OK;
3013 HRESULT
3014 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
3015 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
3016 DWORD dwFlags, LPDDBLTFX lpbltfx)
3018 WINE_GL_BUFFER_TYPE buffer_type;
3019 D3DRECT rect;
3021 if (rdst) {
3022 rect.u1.x1 = rdst->left;
3023 rect.u2.y1 = rdst->top;
3024 rect.u3.x2 = rdst->right;
3025 rect.u4.y2 = rdst->bottom;
3026 } else {
3027 rect.u1.x1 = 0;
3028 rect.u2.y1 = 0;
3029 rect.u3.x2 = This->surface_desc.dwWidth;
3030 rect.u4.y2 = This->surface_desc.dwHeight;
3033 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
3035 if (dwFlags & DDBLT_COLORFILL) {
3036 /* This is easy to handle for the D3D Device... */
3037 DWORD color;
3038 GLint prev_draw;
3040 /* The color as given in the Blt function is in the format of the frame-buffer...
3041 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3043 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
3044 if (This->palette) {
3045 color = ((0xFF000000) |
3046 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
3047 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
3048 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
3049 } else {
3050 color = 0xFF000000;
3052 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
3053 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3054 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3055 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3056 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3057 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3058 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3059 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
3060 color = 0xFFFFFFFF;
3061 } else {
3062 color = ((0xFF000000) |
3063 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
3064 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
3065 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
3067 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
3068 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
3069 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3070 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3071 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3072 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
3073 } else {
3074 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
3075 return DDERR_INVALIDPARAMS;
3077 } else {
3078 ERR("Wrong surface type for BLT override !\n");
3079 return DDERR_INVALIDPARAMS;
3082 TRACE(" executing D3D Device override.\n");
3084 ENTER_GL();
3086 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3087 if (buffer_type == WINE_GL_BUFFER_FRONT)
3088 glDrawBuffer(GL_FRONT);
3089 else
3090 glDrawBuffer(GL_BACK);
3092 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
3094 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3095 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3096 glDrawBuffer(prev_draw);
3098 LEAVE_GL();
3100 return DD_OK;
3101 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
3102 /* Normal blit without any special case... */
3103 if (src != NULL) {
3104 /* And which has a SRC surface */
3105 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3107 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3108 (src_impl->d3ddevice == This->d3ddevice) &&
3109 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3110 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3111 D3DRECT src_rect;
3112 int width, height;
3113 GLint prev_draw;
3114 WINE_GL_BUFFER_TYPE src_buffer_type;
3115 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3116 BOOLEAN initial;
3117 DWORD opt_bitmap;
3118 int x, y;
3120 if (rsrc) {
3121 src_rect.u1.x1 = rsrc->left;
3122 src_rect.u2.y1 = rsrc->top;
3123 src_rect.u3.x2 = rsrc->right;
3124 src_rect.u4.y2 = rsrc->bottom;
3125 } else {
3126 src_rect.u1.x1 = 0;
3127 src_rect.u2.y1 = 0;
3128 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3129 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3132 width = src_rect.u3.x2 - src_rect.u1.x1;
3133 height = src_rect.u4.y2 - src_rect.u2.y1;
3135 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3136 (height != (rect.u4.y2 - rect.u2.y1))) {
3137 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3138 return DDERR_INVALIDPARAMS;
3141 /* First check if we BLT from the backbuffer... */
3142 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3143 src_buffer_type = WINE_GL_BUFFER_BACK;
3144 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3145 src_buffer_type = WINE_GL_BUFFER_FRONT;
3146 } else {
3147 ERR("Unexpected case in direct buffer to buffer copy !\n");
3148 return DDERR_INVALIDPARAMS;
3151 TRACE(" using direct buffer to buffer copy.\n");
3153 ENTER_GL();
3155 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3157 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3158 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3159 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3160 LEAVE_GL();
3161 return DDERR_INVALIDPARAMS;
3164 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3165 if (buffer_type == WINE_GL_BUFFER_FRONT)
3166 glDrawBuffer(GL_FRONT);
3167 else
3168 glDrawBuffer(GL_BACK);
3170 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3171 glReadBuffer(GL_FRONT);
3172 else
3173 glReadBuffer(GL_BACK);
3175 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3176 And directly re-draws this on the destination buffer. */
3177 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3178 int get_height;
3180 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3181 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3182 else
3183 get_height = UNLOCK_TEX_SIZE;
3185 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3186 int get_width;
3188 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3189 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3190 else
3191 get_width = UNLOCK_TEX_SIZE;
3193 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3194 0, UNLOCK_TEX_SIZE - get_height,
3195 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3196 get_width, get_height);
3198 glBegin(GL_QUADS);
3199 glTexCoord2f(0.0, 0.0);
3200 glVertex3d(rect.u1.x1 + x,
3201 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3202 0.5);
3203 glTexCoord2f(1.0, 0.0);
3204 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3205 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3206 0.5);
3207 glTexCoord2f(1.0, 1.0);
3208 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3209 rect.u2.y1 + y,
3210 0.5);
3211 glTexCoord2f(0.0, 1.0);
3212 glVertex3d(rect.u1.x1 + x,
3213 rect.u2.y1 + y,
3214 0.5);
3215 glEnd();
3219 upload_surface_to_tex_memory_release();
3220 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3222 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3223 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3224 glDrawBuffer(prev_draw);
3226 LEAVE_GL();
3228 return DD_OK;
3229 } else {
3230 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3231 (this prevents calling glReadPixels) */
3232 D3DRECT src_rect;
3233 int width, height;
3234 GLint prev_draw;
3235 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3236 BOOLEAN initial;
3237 DWORD opt_bitmap;
3238 int x, y;
3239 double x_stretch, y_stretch;
3241 if (rsrc) {
3242 src_rect.u1.x1 = rsrc->left;
3243 src_rect.u2.y1 = rsrc->top;
3244 src_rect.u3.x2 = rsrc->right;
3245 src_rect.u4.y2 = rsrc->bottom;
3246 } else {
3247 src_rect.u1.x1 = 0;
3248 src_rect.u2.y1 = 0;
3249 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3250 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3253 width = src_rect.u3.x2 - src_rect.u1.x1;
3254 height = src_rect.u4.y2 - src_rect.u2.y1;
3256 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3257 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3259 TRACE(" using memory to buffer Blt override.\n");
3261 ENTER_GL();
3263 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3265 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3266 initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3267 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3268 LEAVE_GL();
3269 return DDERR_INVALIDPARAMS;
3272 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3273 if (buffer_type == WINE_GL_BUFFER_FRONT)
3274 glDrawBuffer(GL_FRONT);
3275 else
3276 glDrawBuffer(GL_BACK);
3278 /* Now the serious stuff happens. This is basically the same code as for the memory
3279 flush to frame buffer ... with stretching and different rectangles added :-) */
3280 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3281 RECT flush_rect;
3283 flush_rect.top = src_rect.u2.y1 + y;
3284 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3285 src_rect.u4.y2 :
3286 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3288 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3289 flush_rect.left = src_rect.u1.x1 + x;
3290 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3291 src_rect.u3.x2 :
3292 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3294 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3296 glBegin(GL_QUADS);
3297 glTexCoord2f(0.0, 0.0);
3298 glVertex3d(rect.u1.x1 + (x * x_stretch),
3299 rect.u2.y1 + (y * y_stretch),
3300 0.5);
3301 glTexCoord2f(1.0, 0.0);
3302 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3303 rect.u2.y1 + (y * y_stretch),
3304 0.5);
3305 glTexCoord2f(1.0, 1.0);
3306 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3307 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3308 0.5);
3309 glTexCoord2f(0.0, 1.0);
3310 glVertex3d(rect.u1.x1 + (x * x_stretch),
3311 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3312 0.5);
3313 glEnd();
3317 upload_surface_to_tex_memory_release();
3318 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3320 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3321 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3322 glDrawBuffer(prev_draw);
3324 LEAVE_GL();
3326 return DD_OK;
3330 return DDERR_INVALIDPARAMS;
3333 HRESULT
3334 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3335 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3336 LPRECT rsrc, DWORD trans)
3338 RECT rsrc2;
3339 RECT rdst;
3340 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3341 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3342 WINE_GL_BUFFER_TYPE buffer_type;
3343 GLint prev_draw;
3344 DWORD opt_bitmap;
3345 BOOLEAN initial;
3346 int width, height, x, y;
3348 /* Cannot support DSTCOLORKEY blitting... */
3349 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3351 if (rsrc == NULL) {
3352 WARN("rsrc is NULL - getting the whole surface !!\n");
3353 rsrc = &rsrc2;
3354 rsrc->left = rsrc->top = 0;
3355 rsrc->right = src_impl->surface_desc.dwWidth;
3356 rsrc->bottom = src_impl->surface_desc.dwHeight;
3357 } else {
3358 rsrc2 = *rsrc;
3359 rsrc = &rsrc2;
3362 rdst.left = dstx;
3363 rdst.top = dsty;
3364 rdst.right = dstx + (rsrc->right - rsrc->left);
3365 if (rdst.right > This->surface_desc.dwWidth) {
3366 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3367 rdst.right = This->surface_desc.dwWidth;
3369 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3370 if (rdst.bottom > This->surface_desc.dwHeight) {
3371 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3372 rdst.bottom = This->surface_desc.dwHeight;
3375 width = rsrc->right - rsrc->left;
3376 height = rsrc->bottom - rsrc->top;
3378 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3380 TRACE(" using BltFast memory to frame buffer override.\n");
3382 ENTER_GL();
3384 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3386 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3387 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3388 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3389 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3390 LEAVE_GL();
3391 return DDERR_INVALIDPARAMS;
3394 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3395 if (buffer_type == WINE_GL_BUFFER_FRONT)
3396 glDrawBuffer(GL_FRONT);
3397 else
3398 glDrawBuffer(GL_BACK);
3400 /* Now the serious stuff happens. This is basically the same code that for the memory
3401 flush to frame buffer but with different rectangles for source and destination :-) */
3402 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3403 RECT flush_rect;
3405 flush_rect.top = rsrc->top + y;
3406 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3407 rsrc->bottom :
3408 (rsrc->top + y + UNLOCK_TEX_SIZE));
3410 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3411 flush_rect.left = rsrc->left + x;
3412 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3413 rsrc->right :
3414 (rsrc->left + x + UNLOCK_TEX_SIZE));
3416 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3418 glBegin(GL_QUADS);
3419 glTexCoord2f(0.0, 0.0);
3420 glVertex3d(rdst.left + x,
3421 rdst.top + y,
3422 0.5);
3423 glTexCoord2f(1.0, 0.0);
3424 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3425 rdst.top + y,
3426 0.5);
3427 glTexCoord2f(1.0, 1.0);
3428 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3429 rdst.top + (y + UNLOCK_TEX_SIZE),
3430 0.5);
3431 glTexCoord2f(0.0, 1.0);
3432 glVertex3d(rdst.left + x,
3433 rdst.top + (y + UNLOCK_TEX_SIZE),
3434 0.5);
3435 glEnd();
3439 upload_surface_to_tex_memory_release();
3440 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3442 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3443 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3444 glDrawBuffer(prev_draw);
3446 LEAVE_GL();
3448 return DD_OK;
3451 void
3452 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3454 GLfloat height, width;
3455 GLfloat trans_mat[16];
3457 TRACE("(%p)\n", This);
3459 width = This->surface->surface_desc.dwWidth;
3460 height = This->surface->surface_desc.dwHeight;
3462 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3463 * to OpenGL screen coordinates (ie the upper left corner is not the same).
3465 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3466 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3467 #if 0
3468 /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3469 * that the Z coordinate needs to be given to GL unchanged.
3471 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 2.0; trans_mat[14] = -1.0;
3472 #endif
3473 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = 0.0;
3474 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3476 ENTER_GL();
3477 glMatrixMode(GL_MODELVIEW);
3478 glLoadIdentity();
3479 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3480 Correctness Tips section).
3482 Basically, from what I understood, if the game does not filter the font texture,
3483 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3484 one and we will have strange artifacts (as the rounding and stuff may give different results
3485 for different pixels, ie sometimes take the left pixel, sometimes the right).
3487 glTranslatef(0.375, 0.375, 0);
3488 glMatrixMode(GL_PROJECTION);
3489 glLoadMatrixf(trans_mat);
3490 LEAVE_GL();
3493 void
3494 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3495 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3497 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3499 ENTER_GL();
3500 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3501 glMatrixMode(GL_MODELVIEW);
3502 glLoadMatrixf((float *) view_mat);
3504 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3505 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3506 GLint i;
3507 DWORD runner;
3508 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3509 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3510 GLdouble plane[4];
3512 plane[0] = This->clipping_planes[i].plane[0];
3513 plane[1] = This->clipping_planes[i].plane[1];
3514 plane[2] = This->clipping_planes[i].plane[2];
3515 plane[3] = This->clipping_planes[i].plane[3];
3517 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3521 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3522 GLint i;
3524 for (i = 0; i < This->max_active_lights; i++ )
3526 DWORD dwLightIndex = This->active_lights[i];
3527 if (dwLightIndex != ~0)
3529 LPD3DLIGHT7 pLight = &This->light_parameters[dwLightIndex];
3530 switch (pLight->dltType)
3532 case D3DLIGHT_DIRECTIONAL: {
3533 float direction[4];
3534 float cut_off = 180.0;
3536 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3537 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3538 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3539 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3541 direction[0] = pLight->dvDirection.u1.x;
3542 direction[1] = pLight->dvDirection.u2.y;
3543 direction[2] = pLight->dvDirection.u3.z;
3544 direction[3] = 0.0;
3545 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3546 } break;
3548 case D3DLIGHT_POINT: {
3549 float position[4];
3550 float cut_off = 180.0;
3552 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3553 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3554 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3555 position[0] = pLight->dvPosition.u1.x;
3556 position[1] = pLight->dvPosition.u2.y;
3557 position[2] = pLight->dvPosition.u3.z;
3558 position[3] = 1.0;
3559 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3560 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3561 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3562 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3563 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3564 } break;
3566 case D3DLIGHT_SPOT: {
3567 float direction[4];
3568 float position[4];
3569 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3571 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3572 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3573 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3575 direction[0] = pLight->dvDirection.u1.x;
3576 direction[1] = pLight->dvDirection.u2.y;
3577 direction[2] = pLight->dvDirection.u3.z;
3578 direction[3] = 0.0;
3579 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3580 position[0] = pLight->dvPosition.u1.x;
3581 position[1] = pLight->dvPosition.u2.y;
3582 position[2] = pLight->dvPosition.u3.z;
3583 position[3] = 1.0;
3584 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3585 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3586 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3587 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3588 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3589 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &pLight->dvFalloff);
3590 } break;
3592 default:
3593 /* No warning here as it's already done at light setting */
3594 break;
3600 glMultMatrixf((float *) world_mat);
3602 if ((matrices & PROJMAT_CHANGED) != 0) {
3603 glMatrixMode(GL_PROJECTION);
3604 glLoadMatrixf((float *) proj_mat);
3606 LEAVE_GL();
3609 void
3610 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3612 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3613 DWORD tex_mat, tex_stage;
3615 TRACE("(%p,%08lx)\n", This, matrices);
3617 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3618 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3619 /* This will force an update of the transform state at the next drawing. */
3620 glThis->transform_state = GL_TRANSFORM_NONE;
3623 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3624 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3626 ENTER_GL();
3627 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3628 GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3629 if (matrices & tex_mat) {
3630 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3631 int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3633 if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3634 if (glThis->current_active_tex_unit != unit) {
3635 GL_extensions.glActiveTexture(unit);
3636 glThis->current_active_tex_unit = unit;
3638 glMatrixMode(GL_TEXTURE);
3639 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3641 This->tex_mat_is_identity[tex_stage] = is_identity;
3642 } else {
3643 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3644 if (glThis->current_active_tex_unit != unit) {
3645 GL_extensions.glActiveTexture(unit);
3646 glThis->current_active_tex_unit = unit;
3648 glMatrixMode(GL_TEXTURE);
3649 glLoadIdentity();
3650 This->tex_mat_is_identity[tex_stage] = TRUE;
3655 LEAVE_GL();
3659 /* TODO for both these functions :
3660 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3661 by other OpenGL code in D3D
3662 - handle the case where no 'Begin / EndScene' was done between two locks
3663 - handle the rectangles in the unlock too
3664 - handle pitch correctly...
3666 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3668 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3669 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3670 WINE_GL_BUFFER_TYPE buffer_type;
3671 RECT loc_rect;
3673 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3674 buffer_type = WINE_GL_BUFFER_FRONT;
3675 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3676 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3677 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3679 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3680 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3681 buffer_type = WINE_GL_BUFFER_BACK;
3682 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3683 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3684 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3686 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3687 } else {
3688 ERR("Wrong surface type for locking !\n");
3689 return;
3692 if (pRect == NULL) {
3693 loc_rect.top = 0;
3694 loc_rect.left = 0;
3695 loc_rect.bottom = This->surface_desc.dwHeight;
3696 loc_rect.right = This->surface_desc.dwWidth;
3697 pRect = &loc_rect;
3700 /* Try to acquire the device critical section */
3701 EnterCriticalSection(&(d3d_dev->crit));
3703 if (gl_d3d_dev->lock_rect_valid[buffer_type]) {
3704 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3705 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3707 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3709 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3710 /* Check if the new rectangle is in the previous one or not.
3711 If it is not, flush first the previous locks on screen.
3713 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3714 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3715 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3716 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3717 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3718 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3719 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3720 pRect->left, pRect->top, pRect->right, pRect->bottom,
3721 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3722 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3723 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3725 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3726 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3728 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3729 } else {
3730 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3733 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3734 /* If the surface is already in memory, no need to do anything here... */
3735 GLenum buffer_format;
3736 GLenum buffer_color;
3737 int y;
3738 char *dst;
3740 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3741 pRect->left, pRect->top, pRect->right, pRect->bottom);
3743 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3744 may only write to the device... But when we will blit it back to the screen, we need
3745 also to blit correctly the parts the application did not overwrite... */
3747 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3748 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3749 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3750 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3751 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3752 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3753 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3754 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3755 buffer_color = GL_RGB;
3756 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3757 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3758 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3759 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3760 buffer_format = GL_UNSIGNED_BYTE;
3761 buffer_color = GL_RGB;
3762 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3763 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3764 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3765 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3766 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3767 buffer_color = GL_BGRA;
3768 } else {
3769 ERR(" unsupported pixel format at device locking.\n");
3770 return;
3772 } else {
3773 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3774 return;
3777 ENTER_GL();
3779 if (buffer_type == WINE_GL_BUFFER_FRONT)
3780 /* Application wants to lock the front buffer */
3781 glReadBuffer(GL_FRONT);
3782 else
3783 /* Application wants to lock the back buffer */
3784 glReadBuffer(GL_BACK);
3786 dst = ((char *)This->surface_desc.lpSurface) +
3787 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3789 if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3790 /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3791 * could not be bothered considering the rare cases where it may be useful :-)
3793 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3794 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3795 y--) {
3796 glReadPixels(pRect->left, y,
3797 pRect->right - pRect->left, 1,
3798 buffer_color, buffer_format, dst);
3799 dst += This->surface_desc.u1.lPitch;
3801 } else {
3802 /* Faster path for surface copy. Note that I can use static variables here as I am
3803 * protected by the OpenGL critical section so this function won't be called by
3804 * two threads at the same time.
3806 static char *buffer = NULL;
3807 static int buffer_width = 0;
3808 char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3809 int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3811 glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3812 pRect->right - pRect->left, pRect->bottom - pRect->top,
3813 buffer_color, buffer_format, dst);
3815 if (current_width > buffer_width) {
3816 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3817 buffer_width = current_width;
3818 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3820 for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3821 memcpy(buffer, dst, current_width);
3822 memcpy(dst, dst2, current_width);
3823 memcpy(dst2, buffer, current_width);
3824 dst += This->surface_desc.u1.lPitch;
3825 dst2 -= This->surface_desc.u1.lPitch;
3829 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3831 #if 0
3832 /* I keep this code here as it's very useful to debug :-) */
3834 static int flush_count = 0;
3835 char buf[128];
3836 FILE *f;
3838 if ((++flush_count % 50) == 0) {
3839 sprintf(buf, "lock_%06d.pnm", flush_count);
3840 f = fopen(buf, "wb");
3841 DDRAW_dump_surface_to_disk(This, f);
3844 #endif
3846 LEAVE_GL();
3850 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3851 RECT loc_rect;
3852 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3853 int x, y;
3854 BOOLEAN initial;
3855 DWORD opt_bitmap;
3857 /* Note : no need here to lock the 'device critical section' as we are already protected by
3858 the GL critical section. */
3860 if (pRect == NULL) {
3861 loc_rect.top = 0;
3862 loc_rect.left = 0;
3863 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3864 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3865 pRect = &loc_rect;
3868 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3870 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3872 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3873 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3874 ERR(" unsupported pixel format at frame buffer flush.\n");
3875 return;
3878 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3879 RECT flush_rect;
3881 flush_rect.top = y;
3882 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3884 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3885 /* First, upload the texture... */
3886 flush_rect.left = x;
3887 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3889 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3891 glBegin(GL_QUADS);
3892 glTexCoord2f(0.0, 0.0);
3893 glVertex3d(x, y, 0.5);
3894 glTexCoord2f(1.0, 0.0);
3895 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3896 glTexCoord2f(1.0, 1.0);
3897 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3898 glTexCoord2f(0.0, 1.0);
3899 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3900 glEnd();
3904 upload_surface_to_tex_memory_release();
3905 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3907 #if 0
3908 /* I keep this code here as it's very useful to debug :-) */
3910 static int flush_count = 0;
3911 char buf[128];
3912 FILE *f;
3914 if ((++flush_count % 50) == 0) {
3915 sprintf(buf, "flush_%06d.pnm", flush_count);
3916 f = fopen(buf, "wb");
3917 DDRAW_dump_surface_to_disk(surf, f);
3920 #endif
3923 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3925 WINE_GL_BUFFER_TYPE buffer_type;
3926 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3927 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3929 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3930 buffer_type = WINE_GL_BUFFER_FRONT;
3931 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3932 buffer_type = WINE_GL_BUFFER_BACK;
3933 } else {
3934 ERR("Wrong surface type for locking !\n");
3935 return;
3938 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3939 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3940 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3942 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3944 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3945 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3946 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3947 GLint prev_draw;
3949 TRACE(" flushing front buffer immediately on screen.\n");
3951 ENTER_GL();
3952 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3953 glDrawBuffer(GL_FRONT);
3954 /* Note: we do not use the application provided lock rectangle but our own stored at
3955 lock time. This is because in old D3D versions, the 'lock' parameter did not
3956 exist.
3958 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]);
3959 glDrawBuffer(prev_draw);
3960 LEAVE_GL();
3961 } else {
3962 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3966 /* And 'frees' the device critical section */
3967 LeaveCriticalSection(&(d3d_dev->crit));
3970 static void
3971 apply_texture_state(IDirect3DDeviceImpl *This)
3973 int stage, state;
3975 /* Initialize texture stages states */
3976 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3977 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3978 if (This->state_block.set_flags.texture_stage_state[stage][state]) {
3979 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3980 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3986 HRESULT
3987 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, int version)
3989 IDirect3DDeviceImpl *object;
3990 IDirect3DDeviceGLImpl *gl_object;
3991 IDirectDrawSurfaceImpl *surf;
3992 HDC device_context;
3993 XVisualInfo *vis;
3994 int num;
3995 int tex_num;
3996 XVisualInfo template;
3997 GLenum buffer = GL_FRONT;
3998 int light;
4000 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
4001 if (object == NULL) return DDERR_OUTOFMEMORY;
4003 gl_object = (IDirect3DDeviceGLImpl *) object;
4005 object->ref = 1;
4006 object->d3d = d3d;
4007 object->surface = surface;
4008 object->set_context = set_context;
4009 object->clear = d3ddevice_clear_back;
4010 object->set_matrices = d3ddevice_set_matrices;
4011 object->matrices_updated = d3ddevice_matrices_updated;
4012 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
4013 object->version = version;
4015 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
4017 InitializeCriticalSection(&(object->crit));
4019 TRACE(" device critical section : %p\n", &(object->crit));
4021 device_context = GetDC(surface->ddraw_owner->window);
4022 gl_object->display = get_display(device_context);
4023 gl_object->drawable = get_drawable(device_context);
4024 ReleaseDC(surface->ddraw_owner->window,device_context);
4026 ENTER_GL();
4027 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
4028 vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
4029 if (vis == NULL) {
4030 HeapFree(GetProcessHeap(), 0, object);
4031 ERR("No visual found !\n");
4032 LEAVE_GL();
4033 return DDERR_INVALIDPARAMS;
4034 } else {
4035 TRACE(" visual found\n");
4038 gl_object->gl_context = glXCreateContext(gl_object->display, vis,
4039 NULL, GL_TRUE);
4041 if (gl_object->gl_context == NULL) {
4042 HeapFree(GetProcessHeap(), 0, object);
4043 ERR("Error in context creation !\n");
4044 LEAVE_GL();
4045 return DDERR_INVALIDPARAMS;
4046 } else {
4047 TRACE(" context created (%p)\n", gl_object->gl_context);
4050 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
4051 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4052 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
4053 surf->aux_ctx = (LPVOID) object;
4054 surf->aux_data = (LPVOID) gl_object->drawable;
4055 surf->aux_flip = opengl_flip;
4056 buffer = GL_BACK;
4057 break;
4060 /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
4061 if (surf == NULL) {
4062 TRACE(" no double buffering : drawing on the front buffer\n");
4063 buffer = GL_FRONT;
4066 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4067 IDirectDrawSurfaceImpl *surf2;
4068 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
4069 for (; surf2 != NULL; surf2 = surf2->next_attached) {
4070 TRACE(" checking surface %p :", surf2);
4071 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
4072 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
4073 /* Override the Lock / Unlock function for all these surfaces */
4074 surf2->lock_update_prev = surf2->lock_update;
4075 surf2->lock_update = d3ddevice_lock_update;
4076 surf2->unlock_update_prev = surf2->unlock_update;
4077 surf2->unlock_update = d3ddevice_unlock_update;
4078 /* And install also the blt / bltfast overrides */
4079 surf2->aux_blt = d3ddevice_blt;
4080 surf2->aux_bltfast = d3ddevice_bltfast;
4082 TRACE(" overriding direct surface access.\n");
4083 } else {
4084 TRACE(" no override.\n");
4086 surf2->d3ddevice = object;
4090 /* Set the various light parameters */
4091 object->num_set_lights = 0;
4092 object->max_active_lights = opengl_device_caps.dwMaxActiveLights;
4093 object->light_parameters = NULL;
4094 object->active_lights = HeapAlloc(GetProcessHeap(), 0,
4095 object->max_active_lights * sizeof(object->active_lights[0]));
4096 /* Fill the active light array with ~0, which is used to indicate an
4097 invalid light index. We don't use 0, because it's a valid light index. */
4098 for (light=0; light < object->max_active_lights; light++)
4099 object->active_lights[light] = ~0;
4102 /* Allocate memory for the matrices */
4103 object->world_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4104 object->view_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4105 object->proj_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4106 memcpy(object->world_mat, id_mat, 16 * sizeof(float));
4107 memcpy(object->view_mat , id_mat, 16 * sizeof(float));
4108 memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
4109 for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
4110 object->tex_mat[tex_num] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4111 memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
4112 object->tex_mat_is_identity[tex_num] = TRUE;
4115 /* Initialisation */
4116 TRACE(" setting current context\n");
4117 object->set_context(object);
4118 TRACE(" current context set\n");
4120 /* allocate the clipping planes */
4121 object->max_clipping_planes = opengl_device_caps.wMaxUserClipPlanes;
4122 object->clipping_planes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
4124 glHint(GL_FOG_HINT,GL_NICEST);
4126 /* Initialize the various GL contexts to be in sync with what we store locally */
4127 glClearDepth(0.0);
4128 glClearStencil(0);
4129 glClearColor(0.0, 0.0, 0.0, 0.0);
4130 glDepthMask(GL_TRUE);
4131 gl_object->depth_mask = TRUE;
4132 glEnable(GL_DEPTH_TEST);
4133 gl_object->depth_test = TRUE;
4134 glDisable(GL_ALPHA_TEST);
4135 glDisable(GL_STENCIL_TEST);
4136 glDisable(GL_CULL_FACE);
4137 glDisable(GL_LIGHTING);
4138 glDisable(GL_BLEND);
4139 glDisable(GL_FOG);
4140 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4141 gl_object->current_tex_env = GL_REPLACE;
4142 gl_object->current_active_tex_unit = GL_TEXTURE0_WINE;
4143 if (GL_extensions.glActiveTexture != NULL) {
4144 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
4146 gl_object->current_alpha_test_ref = 0.0;
4147 gl_object->current_alpha_test_func = GL_ALWAYS;
4148 glAlphaFunc(GL_ALWAYS, 0.0);
4150 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4151 glDrawBuffer(buffer);
4152 glReadBuffer(buffer);
4153 /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
4154 LEAVE_GL();
4156 gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
4157 gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
4159 /* fill_device_capabilities(d3d->ddraw); */
4161 ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
4162 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
4163 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
4164 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
4166 *obj = object;
4168 TRACE(" creating implementation at %p.\n", *obj);
4170 /* And finally warn D3D that this device is now present */
4171 object->d3d->d3d_added_device(object->d3d, object);
4173 InitDefaultStateBlock(&object->state_block, object->version);
4174 /* Apply default render state and texture stage state values */
4175 apply_render_state(object, &object->state_block);
4176 apply_texture_state(object);
4178 /* And fill the fog table with the default fog value */
4179 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4181 return DD_OK;
4184 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4186 pc->dwSize = sizeof(*pc);
4187 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4188 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4189 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4190 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4191 D3DPRASTERCAPS_ZFOG;
4192 if (GL_extensions.mipmap_lodbias) {
4193 pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4195 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4196 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4197 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4198 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4199 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4200 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4201 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4202 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4203 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4204 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4205 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4206 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4207 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4208 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4209 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4210 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4211 D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4212 D3DPTFILTERCAPS_MIPFPOINT;
4213 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4214 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4215 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4216 if (GL_extensions.mirrored_repeat) {
4217 pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4219 pc->dwStippleWidth = 32;
4220 pc->dwStippleHeight = 32;
4223 static void fill_caps(void)
4225 GLint max_clip_planes;
4226 GLint depth_bits;
4228 /* Fill first all the fields with default values which will be overriden later on with
4229 correct ones from the GL code
4231 opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4232 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4233 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4234 /* D3D 7 capabilities */
4235 D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4236 fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4237 fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4238 opengl_device_caps.dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
4239 opengl_device_caps.dwMinTextureWidth = 1;
4240 opengl_device_caps.dwMinTextureHeight = 1;
4241 opengl_device_caps.dwMaxTextureWidth = 1024;
4242 opengl_device_caps.dwMaxTextureHeight = 1024;
4243 opengl_device_caps.dwMaxTextureRepeat = 16;
4244 opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4245 opengl_device_caps.dwMaxAnisotropy = 0;
4246 opengl_device_caps.dvGuardBandLeft = 0.0;
4247 opengl_device_caps.dvGuardBandRight = 0.0;
4248 opengl_device_caps.dvGuardBandTop = 0.0;
4249 opengl_device_caps.dvGuardBandBottom = 0.0;
4250 opengl_device_caps.dvExtentsAdjust = 0.0;
4251 opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4252 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4253 opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4254 D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4255 D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4256 if (GL_extensions.max_texture_units != 0) {
4257 opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4258 opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4259 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4260 } else {
4261 opengl_device_caps.wMaxTextureBlendStages = 1;
4262 opengl_device_caps.wMaxSimultaneousTextures = 1;
4263 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4265 opengl_device_caps.dwMaxActiveLights = 16;
4266 opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4267 opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4268 opengl_device_caps.wMaxUserClipPlanes = 1;
4269 opengl_device_caps.wMaxVertexBlendMatrices = 0;
4270 opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4271 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4272 opengl_device_caps.dwReserved1 = 0;
4273 opengl_device_caps.dwReserved2 = 0;
4274 opengl_device_caps.dwReserved3 = 0;
4275 opengl_device_caps.dwReserved4 = 0;
4277 /* And now some GL overrides :-) */
4278 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4279 opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4280 opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4281 TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4283 glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4284 TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4286 glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4287 opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4288 TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4290 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4291 TRACE(": Z bits = %d\n", depth_bits);
4292 switch (depth_bits) {
4293 case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4294 case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4295 case 32:
4296 default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4300 BOOL
4301 d3ddevice_init_at_startup(void *gl_handle)
4303 XVisualInfo template;
4304 XVisualInfo *vis;
4305 HDC device_context;
4306 Display *display;
4307 Visual *visual;
4308 Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4309 XWindowAttributes win_attr;
4310 GLXContext gl_context;
4311 int num;
4312 const char *glExtensions;
4313 const char *glVersion;
4314 const char *glXExtensions = NULL;
4315 const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4316 int major, minor, patch, num_parsed;
4318 TRACE("Initializing GL...\n");
4320 if (!drawable)
4322 WARN("x11drv not loaded - D3D support disabled!\n");
4323 return FALSE;
4326 /* Get a default rendering context to have the 'caps' function query some info from GL */
4327 device_context = GetDC(0);
4328 display = get_display(device_context);
4329 ReleaseDC(0, device_context);
4331 ENTER_GL();
4332 if (XGetWindowAttributes(display, drawable, &win_attr)) {
4333 visual = win_attr.visual;
4334 } else {
4335 visual = DefaultVisual(display, DefaultScreen(display));
4337 template.visualid = XVisualIDFromVisual(visual);
4338 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4339 if (vis == NULL) {
4340 LEAVE_GL();
4341 WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4342 return FALSE;
4344 gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4345 XFree(vis);
4347 if (gl_context == NULL) {
4348 LEAVE_GL();
4349 WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4350 return FALSE;
4352 if (glXMakeCurrent(display, drawable, gl_context) == False) {
4353 glXDestroyContext(display, gl_context);
4354 LEAVE_GL();
4355 WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4356 return FALSE;
4359 /* Then, query all extensions */
4360 glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4361 glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4362 glVersion = (const char *) glGetString(GL_VERSION);
4363 if (gl_handle != NULL) {
4364 pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4367 /* Parse the GL version string */
4368 num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4369 if (num_parsed == 1) {
4370 minor = 0;
4371 patch = 0;
4372 } else if (num_parsed == 2) {
4373 patch = 0;
4375 TRACE("GL version %d.%d.%d\n", major, minor, patch);
4377 /* And starts to fill the extension context properly */
4378 memset(&GL_extensions, 0, sizeof(GL_extensions));
4379 TRACE("GL supports following extensions used by Wine :\n");
4381 /* Mirrored Repeat extension :
4382 - GL_ARB_texture_mirrored_repeat
4383 - GL_IBM_texture_mirrored_repeat
4384 - GL >= 1.4
4386 if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4387 (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4388 (major > 1) ||
4389 ((major == 1) && (minor >= 4))) {
4390 TRACE(" - mirrored repeat\n");
4391 GL_extensions.mirrored_repeat = TRUE;
4394 /* Texture LOD Bias :
4395 - GL_EXT_texture_lod_bias
4397 if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4398 TRACE(" - texture lod bias\n");
4399 GL_extensions.mipmap_lodbias = TRUE;
4402 /* For all subsequent extensions, we need glXGetProcAddress */
4403 if (pglXGetProcAddressARB != NULL) {
4404 /* Multi-texturing :
4405 - GL_ARB_multitexture
4406 - GL >= 1.2.1
4408 if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4409 (major > 1) ||
4410 ((major == 1) && (minor > 2)) ||
4411 ((major == 1) && (minor == 2) && (patch >= 1))) {
4412 glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4413 TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4414 /* We query the ARB version to be the most portable we can... */
4415 GL_extensions.glActiveTexture = pglXGetProcAddressARB( (const GLubyte *) "glActiveTextureARB");
4416 GL_extensions.glMultiTexCoord[0] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord1fvARB");
4417 GL_extensions.glMultiTexCoord[1] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord2fvARB");
4418 GL_extensions.glMultiTexCoord[2] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord3fvARB");
4419 GL_extensions.glMultiTexCoord[3] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord4fvARB");
4420 GL_extensions.glClientActiveTexture = pglXGetProcAddressARB( (const GLubyte *) "glClientActiveTextureARB");
4421 } else {
4422 GL_extensions.max_texture_units = 0;
4425 if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4426 TRACE(" - S3TC compression supported\n");
4427 GL_extensions.s3tc_compressed_texture = TRUE;
4428 GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB( (const GLubyte *) "glCompressedTexImage2DARB");
4429 GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB( (const GLubyte *) "glCompressedTexSubImage2DARB");
4433 /* Fill the D3D capabilities according to what GL tells us... */
4434 fill_caps();
4436 /* And frees this now-useless context */
4437 glXMakeCurrent(display, None, NULL);
4438 glXDestroyContext(display, gl_context);
4439 LEAVE_GL();
4441 return TRUE;