Test for return value from CreateDirectory("c:").
[wine/dcerpc.git] / dlls / ddraw / device_opengl.c
blobeaa542d12ba2fd3ae247a2cbba7918e0e55ac295
1 /*
2 * Direct3D Device
4 * Copyright (c) 1998-2004 Lionel Ulmer
5 * Copyright (c) 2002-2005 Christian Costa
7 * This file contains the MESA implementation of all the D3D devices that
8 * Wine supports.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <string.h>
30 #include <math.h>
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "objbase.h"
39 #include "wingdi.h"
40 #include "ddraw.h"
41 #include "d3d.h"
42 #include "wine/debug.h"
43 #include "wine/library.h"
45 #include "d3d_private.h"
46 #include "opengl_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
49 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
51 /* x11drv GDI escapes */
52 #define X11DRV_ESCAPE 6789
53 enum x11drv_escape_codes
55 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
56 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
57 X11DRV_GET_FONT, /* get current X font for a DC */
60 /* They are non-static as they are used by Direct3D in the creation function */
61 const GUID IID_D3DDEVICE_OpenGL = {
62 0x31416d44,
63 0x86ae,
64 0x11d2,
65 { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
68 const float id_mat[16] = {
69 1.0, 0.0, 0.0, 0.0,
70 0.0, 1.0, 0.0, 0.0,
71 0.0, 0.0, 1.0, 0.0,
72 0.0, 0.0, 0.0, 1.0
75 /* This is filled at DLL loading time */
76 static D3DDEVICEDESC7 opengl_device_caps;
77 GL_EXTENSIONS_LIST GL_extensions;
79 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
80 D3DPRIMITIVETYPE d3dptPrimitiveType,
81 DWORD d3dvtVertexType,
82 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
83 DWORD dwVertexCount,
84 LPWORD dwIndices,
85 DWORD dwIndexCount,
86 DWORD dwFlags) ;
88 static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
90 /* retrieve the X display to use on a given DC */
91 inline static Display *get_display( HDC hdc )
93 Display *display;
94 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
96 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
97 sizeof(display), (LPSTR)&display )) display = NULL;
99 return display;
102 #define UNLOCK_TEX_SIZE 256
104 #define DEPTH_RANGE_BIT (0x00000001 << 0)
105 #define VIEWPORT_BIT (0x00000001 << 1)
107 static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
108 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
109 DWORD opt_bitmap = 0x00000000;
111 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
112 ((d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE))) {
113 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
114 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
115 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
117 /* Disable multi-texturing for level 1 to disable all others */
118 glDisable(GL_TEXTURE_2D);
120 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
121 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
122 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
124 if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
125 (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
126 glEnable(GL_TEXTURE_2D);
127 if (gl_d3d_dev->unlock_tex == 0) {
128 glGenTextures(1, &gl_d3d_dev->unlock_tex);
129 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
130 *initial = TRUE;
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
135 } else {
136 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
137 *initial = FALSE;
139 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
140 glMatrixMode(GL_TEXTURE);
141 glLoadIdentity();
144 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
145 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
146 d3ddevice_set_ortho(d3d_dev);
149 if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
150 glEnable(GL_SCISSOR_TEST);
151 if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
152 (d3d_dev->active_viewport.dvMaxZ != 1.0)) {
153 glDepthRange(0.0, 1.0);
154 opt_bitmap |= DEPTH_RANGE_BIT;
156 if ((d3d_dev->active_viewport.dwX != 0) ||
157 (d3d_dev->active_viewport.dwY != 0) ||
158 (d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
159 (d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
160 glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
161 opt_bitmap |= VIEWPORT_BIT;
163 glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
164 pRect->right - pRect->left, pRect->bottom - pRect->top);
165 if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
166 if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
167 if (use_alpha) {
168 if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
169 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
170 glAlphaFunc(GL_NOTEQUAL, 0.0);
171 } else {
172 if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
174 if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
175 if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
176 if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
177 if (gl_d3d_dev->current_tex_env != GL_REPLACE)
178 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
180 return opt_bitmap;
183 static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
184 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
186 /* And restore all the various states modified by this code */
187 if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
188 if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
189 if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
190 glEnable(GL_ALPHA_TEST);
191 else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
192 glDisable(GL_ALPHA_TEST);
193 if (use_alpha) {
194 if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
195 glAlphaFunc(gl_d3d_dev->current_alpha_test_func, gl_d3d_dev->current_alpha_test_ref);
197 if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
198 if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
199 if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
200 if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
201 glDisable(GL_SCISSOR_TEST);
202 if (opt_bitmap & DEPTH_RANGE_BIT) {
203 glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
205 if (opt_bitmap & VIEWPORT_BIT) {
206 glViewport(d3d_dev->active_viewport.dwX,
207 d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
208 d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
210 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
211 d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
214 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
215 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
216 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
218 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
219 /* Note that here we could directly re-bind the previous texture... But it would in some case be a spurious
220 bind if ever the game changes the texture just after.
222 So choose 0x00000001 to postpone the binding to the next time we draw something on screen. */
223 gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
224 if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
226 /* And re-enabled if needed texture level 1 */
227 if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
228 (d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
229 if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
230 GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
231 gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
233 glEnable(GL_TEXTURE_2D);
237 /* retrieve the X drawable to use on a given DC */
238 inline static Drawable get_drawable( HDC hdc )
240 Drawable drawable;
241 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
243 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
244 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
246 return drawable;
249 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
251 IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
252 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
254 TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
255 ENTER_GL();
256 if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
257 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_BACK]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK]);
259 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
260 gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
261 glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
262 LEAVE_GL();
264 return TRUE;
268 /*******************************************************************************
269 * OpenGL static functions
271 static void set_context(IDirect3DDeviceImpl* This)
273 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
275 TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
276 ENTER_GL();
277 if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
278 ERR("Error in setting current context (context %p drawable %ld)!\n",
279 glThis->gl_context, glThis->drawable);
281 LEAVE_GL();
284 static void fill_opengl_caps(D3DDEVICEDESC *d1)
286 d1->dwSize = sizeof(*d1);
287 d1->dwFlags = D3DDD_COLORMODEL | D3DDD_DEVCAPS | D3DDD_TRANSFORMCAPS | D3DDD_BCLIPPING | D3DDD_LIGHTINGCAPS |
288 D3DDD_LINECAPS | D3DDD_TRICAPS | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH |
289 D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT;
290 d1->dcmColorModel = D3DCOLOR_RGB;
291 d1->dwDevCaps = opengl_device_caps.dwDevCaps;
292 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
293 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
294 d1->bClipping = TRUE;
295 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
296 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
297 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
298 d1->dlcLightingCaps.dwNumLights = opengl_device_caps.dwMaxActiveLights;
299 d1->dpcLineCaps = opengl_device_caps.dpcLineCaps;
300 d1->dpcTriCaps = opengl_device_caps.dpcTriCaps;
301 d1->dwDeviceRenderBitDepth = opengl_device_caps.dwDeviceRenderBitDepth;
302 d1->dwDeviceZBufferBitDepth = opengl_device_caps.dwDeviceZBufferBitDepth;
303 d1->dwMaxBufferSize = 0;
304 d1->dwMaxVertexCount = 65536;
305 d1->dwMinTextureWidth = opengl_device_caps.dwMinTextureWidth;
306 d1->dwMinTextureHeight = opengl_device_caps.dwMinTextureHeight;
307 d1->dwMaxTextureWidth = opengl_device_caps.dwMaxTextureWidth;
308 d1->dwMaxTextureHeight = opengl_device_caps.dwMaxTextureHeight;
309 d1->dwMinStippleWidth = 1;
310 d1->dwMinStippleHeight = 1;
311 d1->dwMaxStippleWidth = 32;
312 d1->dwMaxStippleHeight = 32;
313 d1->dwMaxTextureRepeat = opengl_device_caps.dwMaxTextureRepeat;
314 d1->dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureAspectRatio;
315 d1->dwMaxAnisotropy = opengl_device_caps.dwMaxAnisotropy;
316 d1->dvGuardBandLeft = opengl_device_caps.dvGuardBandLeft;
317 d1->dvGuardBandRight = opengl_device_caps.dvGuardBandRight;
318 d1->dvGuardBandTop = opengl_device_caps.dvGuardBandTop;
319 d1->dvGuardBandBottom = opengl_device_caps.dvGuardBandBottom;
320 d1->dvExtentsAdjust = opengl_device_caps.dvExtentsAdjust;
321 d1->dwStencilCaps = opengl_device_caps.dwStencilCaps;
322 d1->dwFVFCaps = opengl_device_caps.dwFVFCaps;
323 d1->dwTextureOpCaps = opengl_device_caps.dwTextureOpCaps;
324 d1->wMaxTextureBlendStages = opengl_device_caps.wMaxTextureBlendStages;
325 d1->wMaxSimultaneousTextures = opengl_device_caps.wMaxSimultaneousTextures;
328 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
330 *d = opengl_device_caps;
333 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
335 D3DDEVICEDESC dref, d1, d2;
336 HRESULT ret_value;
338 /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
339 Let's put the string in a sufficiently sized array in writable memory. */
340 char device_name[50];
341 strcpy(device_name,"direct3d");
343 fill_opengl_caps(&dref);
345 if (version > 1) {
346 /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
347 char interface_name[] = "WINE Reference Direct3DX using OpenGL";
348 TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
349 d1 = dref;
350 d2 = dref;
351 ret_value = cb((LPIID) &IID_IDirect3DRefDevice, interface_name, device_name, &d1, &d2, context);
352 if (ret_value != D3DENUMRET_OK)
353 return ret_value;
357 char interface_name[] = "WINE Direct3DX using OpenGL";
358 TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
359 d1 = dref;
360 d2 = dref;
361 ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, interface_name, device_name, &d1, &d2, context);
362 if (ret_value != D3DENUMRET_OK)
363 return ret_value;
366 return D3DENUMRET_OK;
369 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
371 D3DDEVICEDESC7 ddesc;
372 char interface_name[] = "WINE Direct3D7 using OpenGL";
373 char device_name[] = "Wine D3D7 device";
375 fill_opengl_caps_7(&ddesc);
377 TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
379 return cb(interface_name, device_name, &ddesc, context);
382 static ULONG WINAPI
383 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
385 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
386 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
387 ULONG ref = InterlockedDecrement(&This->ref);
389 TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, ref + 1);
391 if (!ref) {
392 int i;
393 IDirectDrawSurfaceImpl *surface = This->surface, *surf;
395 /* Release texture associated with the device */
396 for (i = 0; i < MAX_TEXTURES; i++) {
397 if (This->current_texture[i] != NULL)
398 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
399 HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
402 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
403 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
404 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
405 surf->aux_ctx = NULL;
406 surf->aux_data = NULL;
407 surf->aux_flip = NULL;
408 break;
411 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
412 IDirectDrawSurfaceImpl *surf2;
413 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
414 for (; surf2 != NULL; surf2 = surf2->next_attached) {
415 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
416 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
417 /* Override the Lock / Unlock function for all these surfaces */
418 surf2->lock_update = surf2->lock_update_prev;
419 surf2->unlock_update = surf2->unlock_update_prev;
420 /* And install also the blt / bltfast overrides */
421 surf2->aux_blt = NULL;
422 surf2->aux_bltfast = NULL;
424 surf2->d3ddevice = NULL;
428 /* And warn the D3D object that this device is no longer active... */
429 This->d3d->d3d_removed_device(This->d3d, This);
431 /* Free light arrays */
432 HeapFree(GetProcessHeap(), 0, This->light_parameters);
433 HeapFree(GetProcessHeap(), 0, This->active_lights);
435 HeapFree(GetProcessHeap(), 0, This->world_mat);
436 HeapFree(GetProcessHeap(), 0, This->view_mat);
437 HeapFree(GetProcessHeap(), 0, This->proj_mat);
439 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
441 DeleteCriticalSection(&(This->crit));
443 ENTER_GL();
444 if (glThis->unlock_tex)
445 glDeleteTextures(1, &(glThis->unlock_tex));
446 glXDestroyContext(glThis->display, glThis->gl_context);
447 LEAVE_GL();
448 HeapFree(GetProcessHeap(), 0, This->clipping_planes);
449 HeapFree(GetProcessHeap(), 0, This->vertex_buffer);
451 HeapFree(GetProcessHeap(), 0, This);
452 return 0;
454 return ref;
457 HRESULT WINAPI
458 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
459 LPD3DDEVICEDESC lpD3DHWDevDesc,
460 LPD3DDEVICEDESC lpD3DHELDevDesc)
462 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
463 D3DDEVICEDESC desc;
464 DWORD dwSize;
466 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
468 fill_opengl_caps(&desc);
469 dwSize = lpD3DHWDevDesc->dwSize;
470 memset(lpD3DHWDevDesc, 0, dwSize);
471 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
473 dwSize = lpD3DHELDevDesc->dwSize;
474 memset(lpD3DHELDevDesc, 0, dwSize);
475 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
477 TRACE(" returning caps : (no dump function yet)\n");
479 return DD_OK;
482 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
483 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
484 LPVOID context, int version)
486 DDSURFACEDESC sdesc;
487 LPDDPIXELFORMAT pformat;
489 /* Do the texture enumeration */
490 sdesc.dwSize = sizeof(DDSURFACEDESC);
491 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
492 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
493 pformat = &(sdesc.ddpfPixelFormat);
494 pformat->dwSize = sizeof(DDPIXELFORMAT);
495 pformat->dwFourCC = 0;
497 TRACE("Enumerating GL_RGBA unpacked (32)\n");
498 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
499 pformat->u1.dwRGBBitCount = 32;
500 pformat->u2.dwRBitMask = 0x00FF0000;
501 pformat->u3.dwGBitMask = 0x0000FF00;
502 pformat->u4.dwBBitMask = 0x000000FF;
503 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
504 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
505 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
507 TRACE("Enumerating GL_RGB unpacked (32)\n");
508 pformat->dwFlags = DDPF_RGB;
509 pformat->u1.dwRGBBitCount = 32;
510 pformat->u2.dwRBitMask = 0x00FF0000;
511 pformat->u3.dwGBitMask = 0x0000FF00;
512 pformat->u4.dwBBitMask = 0x000000FF;
513 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
514 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
515 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
517 TRACE("Enumerating GL_RGB unpacked (24)\n");
518 pformat->dwFlags = DDPF_RGB;
519 pformat->u1.dwRGBBitCount = 24;
520 pformat->u2.dwRBitMask = 0x00FF0000;
521 pformat->u3.dwGBitMask = 0x0000FF00;
522 pformat->u4.dwBBitMask = 0x000000FF;
523 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
524 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
525 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
527 /* Note : even if this is an 'emulated' texture format, it needs to be first
528 as some dumb applications seem to rely on that. */
529 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
530 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
531 pformat->u1.dwRGBBitCount = 16;
532 pformat->u2.dwRBitMask = 0x00007C00;
533 pformat->u3.dwGBitMask = 0x000003E0;
534 pformat->u4.dwBBitMask = 0x0000001F;
535 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
536 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
537 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
539 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
540 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
541 pformat->u1.dwRGBBitCount = 16;
542 pformat->u2.dwRBitMask = 0x00000F00;
543 pformat->u3.dwGBitMask = 0x000000F0;
544 pformat->u4.dwBBitMask = 0x0000000F;
545 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
546 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
547 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
549 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
550 pformat->dwFlags = DDPF_RGB;
551 pformat->u1.dwRGBBitCount = 16;
552 pformat->u2.dwRBitMask = 0x0000F800;
553 pformat->u3.dwGBitMask = 0x000007E0;
554 pformat->u4.dwBBitMask = 0x0000001F;
555 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
556 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
557 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
559 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
560 pformat->dwFlags = DDPF_RGB;
561 pformat->u1.dwRGBBitCount = 16;
562 pformat->u2.dwRBitMask = 0x00007C00;
563 pformat->u3.dwGBitMask = 0x000003E0;
564 pformat->u4.dwBBitMask = 0x0000001F;
565 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
566 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
567 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
569 #if 0
570 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
571 find enumerated, others the last one. And both want to have the ARGB one.
573 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
575 /* See argument about the RGBA format for 'packed' texture formats */
576 TRACE("Enumerating GL_RGBA unpacked (32)\n");
577 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
578 pformat->u1.dwRGBBitCount = 32;
579 pformat->u2.dwRBitMask = 0xFF000000;
580 pformat->u3.dwGBitMask = 0x00FF0000;
581 pformat->u4.dwBBitMask = 0x0000FF00;
582 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
583 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
584 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
586 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
587 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
588 pformat->u1.dwRGBBitCount = 16;
589 pformat->u2.dwRBitMask = 0x0000F000;
590 pformat->u3.dwGBitMask = 0x00000F00;
591 pformat->u4.dwBBitMask = 0x000000F0;
592 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
593 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
594 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
596 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
597 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
598 pformat->u1.dwRGBBitCount = 16;
599 pformat->u2.dwRBitMask = 0x0000F800;
600 pformat->u3.dwGBitMask = 0x000007C0;
601 pformat->u4.dwBBitMask = 0x0000003E;
602 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
603 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
604 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
605 #endif
607 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
608 pformat->dwFlags = DDPF_RGB;
609 pformat->u1.dwRGBBitCount = 8;
610 pformat->u2.dwRBitMask = 0x000000E0;
611 pformat->u3.dwGBitMask = 0x0000001C;
612 pformat->u4.dwBBitMask = 0x00000003;
613 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
614 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
615 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
617 TRACE("Enumerating Paletted (8)\n");
618 pformat->dwFlags = DDPF_PALETTEINDEXED8;
619 pformat->u1.dwRGBBitCount = 8;
620 pformat->u2.dwRBitMask = 0x00000000;
621 pformat->u3.dwGBitMask = 0x00000000;
622 pformat->u4.dwBBitMask = 0x00000000;
623 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
624 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
625 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
627 /* DXT textures only exist for devices created from IDirect3D3 and above */
628 if ((version >= 3) && GL_extensions.s3tc_compressed_texture) {
629 TRACE("Enumerating DXT1\n");
630 pformat->dwFlags = DDPF_FOURCC;
631 pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
632 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
633 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
635 TRACE("Enumerating DXT3\n");
636 pformat->dwFlags = DDPF_FOURCC;
637 pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
638 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
639 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
641 TRACE("Enumerating DXT5\n");
642 pformat->dwFlags = DDPF_FOURCC;
643 pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
644 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
645 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
648 TRACE("End of enumeration\n");
649 return DD_OK;
653 HRESULT
654 d3ddevice_find(IDirectDrawImpl *d3d,
655 LPD3DFINDDEVICESEARCH lpD3DDFS,
656 LPD3DFINDDEVICERESULT lplpD3DDevice)
658 D3DDEVICEDESC desc;
660 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
661 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
662 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
663 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
665 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
666 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
667 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
668 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
669 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
670 TRACE(" no match for this GUID.\n");
671 return DDERR_INVALIDPARAMS;
675 /* Now return our own GUID */
676 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
677 fill_opengl_caps(&desc);
678 lplpD3DDevice->ddHwDesc = desc;
679 lplpD3DDevice->ddSwDesc = desc;
681 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
683 return D3D_OK;
686 HRESULT WINAPI
687 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
688 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
689 LPVOID lpArg)
691 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
692 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
693 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg, This->version);
696 static HRESULT WINAPI
697 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
698 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
699 LPVOID lpArg)
701 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
702 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
703 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg, This->version);
706 static HRESULT WINAPI
707 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
708 D3DRENDERSTATETYPE dwRenderStateType,
709 DWORD dwRenderState)
711 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
712 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
714 /* Call the render state functions */
715 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
716 set_render_state(This, dwRenderStateType, &This->state_block);
718 return DD_OK;
721 static HRESULT WINAPI
722 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
723 D3DRENDERSTATETYPE dwRenderStateType,
724 LPDWORD lpdwRenderState)
726 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
727 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
729 /* Call the render state functions */
730 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
732 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
734 return DD_OK;
737 static HRESULT WINAPI
738 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
739 D3DLIGHTSTATETYPE dwLightStateType,
740 LPDWORD lpdwLightState)
742 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
744 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
746 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
747 TRACE("Unexpected Light State Type\n");
748 return DDERR_INVALIDPARAMS;
751 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
752 *lpdwLightState = This->material;
753 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
754 *lpdwLightState = D3DCOLOR_RGB;
755 } else {
756 D3DRENDERSTATETYPE rs;
757 switch (dwLightStateType) {
758 case D3DLIGHTSTATE_AMBIENT: /* 2 */
759 rs = D3DRENDERSTATE_AMBIENT;
760 break;
761 case D3DLIGHTSTATE_FOGMODE: /* 4 */
762 rs = D3DRENDERSTATE_FOGVERTEXMODE;
763 break;
764 case D3DLIGHTSTATE_FOGSTART: /* 5 */
765 rs = D3DRENDERSTATE_FOGSTART;
766 break;
767 case D3DLIGHTSTATE_FOGEND: /* 6 */
768 rs = D3DRENDERSTATE_FOGEND;
769 break;
770 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
771 rs = D3DRENDERSTATE_FOGDENSITY;
772 break;
773 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
774 rs = D3DRENDERSTATE_COLORVERTEX;
775 break;
776 default:
777 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
778 return DDERR_INVALIDPARAMS;
781 IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
782 rs,lpdwLightState);
785 return DD_OK;
788 static HRESULT WINAPI
789 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
790 D3DLIGHTSTATETYPE dwLightStateType,
791 DWORD dwLightState)
793 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
795 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
797 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
798 TRACE("Unexpected Light State Type\n");
799 return DDERR_INVALIDPARAMS;
802 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
803 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
805 if (mat != NULL) {
806 TRACE(" activating material %p.\n", mat);
807 mat->activate(mat);
808 } else {
809 FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
811 This->material = dwLightState;
812 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
813 switch (dwLightState) {
814 case D3DCOLOR_MONO:
815 ERR("DDCOLOR_MONO should not happen!\n");
816 break;
817 case D3DCOLOR_RGB:
818 /* We are already in this mode */
819 TRACE("Setting color model to RGB (no-op).\n");
820 break;
821 default:
822 ERR("Unknown color model!\n");
823 return DDERR_INVALIDPARAMS;
825 } else {
826 D3DRENDERSTATETYPE rs;
827 switch (dwLightStateType) {
828 case D3DLIGHTSTATE_AMBIENT: /* 2 */
829 rs = D3DRENDERSTATE_AMBIENT;
830 break;
831 case D3DLIGHTSTATE_FOGMODE: /* 4 */
832 rs = D3DRENDERSTATE_FOGVERTEXMODE;
833 break;
834 case D3DLIGHTSTATE_FOGSTART: /* 5 */
835 rs = D3DRENDERSTATE_FOGSTART;
836 break;
837 case D3DLIGHTSTATE_FOGEND: /* 6 */
838 rs = D3DRENDERSTATE_FOGEND;
839 break;
840 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
841 rs = D3DRENDERSTATE_FOGDENSITY;
842 break;
843 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
844 rs = D3DRENDERSTATE_COLORVERTEX;
845 break;
846 default:
847 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
848 return DDERR_INVALIDPARAMS;
851 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
852 rs,dwLightState);
855 return DD_OK;
858 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
860 switch (d3dpt) {
861 case D3DPT_POINTLIST:
862 TRACE(" primitive type is POINTS\n");
863 return GL_POINTS;
865 case D3DPT_LINELIST:
866 TRACE(" primitive type is LINES\n");
867 return GL_LINES;
869 case D3DPT_LINESTRIP:
870 TRACE(" primitive type is LINE_STRIP\n");
871 return GL_LINE_STRIP;
873 case D3DPT_TRIANGLELIST:
874 TRACE(" primitive type is TRIANGLES\n");
875 return GL_TRIANGLES;
877 case D3DPT_TRIANGLESTRIP:
878 TRACE(" primitive type is TRIANGLE_STRIP\n");
879 return GL_TRIANGLE_STRIP;
881 case D3DPT_TRIANGLEFAN:
882 TRACE(" primitive type is TRIANGLE_FAN\n");
883 return GL_TRIANGLE_FAN;
885 default:
886 FIXME("Unhandled primitive %08x\n", d3dpt);
887 return GL_POINTS;
891 /* This function calculate the Z coordinate from Zproj */
892 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
894 float a,b,c,d;
895 /* Assume that X = Y = 0 and W = 1 */
896 a = This->proj_mat->_33;
897 b = This->proj_mat->_34;
898 c = This->proj_mat->_43;
899 d = This->proj_mat->_44;
900 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
901 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
902 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
904 return (d*Zproj - c) / (a - b*Zproj);
907 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
908 int i;
910 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
912 for (i = 0; i < 3; i++) {
913 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
914 DWORD elt;
915 for (elt = 0; elt < 0x10000; elt++) {
916 /* We apply the fog transformation and cache the result */
917 DWORD fog_intensity = elt & 0xFF;
918 DWORD vertex_color = (elt >> 8) & 0xFF;
919 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
924 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
925 BOOLEAN vertex_transformed,
926 BOOLEAN vertex_lit) {
927 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
929 /* Puts GL in the correct lighting / transformation mode */
930 if ((vertex_transformed == FALSE) &&
931 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
932 /* Need to put the correct transformation again if we go from Transformed
933 vertices to non-transformed ones.
935 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
936 This->world_mat, This->view_mat, This->proj_mat);
937 glThis->transform_state = GL_TRANSFORM_NORMAL;
939 } else if (vertex_transformed &&
940 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
941 /* Set our orthographic projection */
942 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
943 glThis->transform_state = GL_TRANSFORM_ORTHO;
944 d3ddevice_set_ortho(This);
948 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
949 if no fogging state change occurred */
950 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
951 if (vertex_transformed) {
952 if (glThis->fogging != 0) {
953 glDisable(GL_FOG);
954 glThis->fogging = 0;
956 /* Now check if our fog_table still corresponds to the current vertex color.
957 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
958 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
959 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
960 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
961 /* We need to rebuild our fog table.... */
962 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
964 } else {
965 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
966 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
967 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
968 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
969 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
971 if (vertex_lit == FALSE) {
972 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
973 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
974 } else {
975 /* Special case of 'pixel fog' */
976 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
977 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
979 if (glThis->fogging == 0) {
980 glEnable(GL_FOG);
981 glThis->fogging = 1;
983 } else {
984 if (glThis->fogging != 0) {
985 glDisable(GL_FOG);
986 glThis->fogging = 0;
990 } else {
991 if (glThis->fogging != 0) {
992 glDisable(GL_FOG);
993 glThis->fogging = 0;
997 /* Handle the 'no-normal' case */
998 if ((vertex_lit == FALSE) && This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1]) {
999 if (glThis->lighting == 0) {
1000 glEnable(GL_LIGHTING);
1001 glThis->lighting = 1;
1003 } else {
1004 if (glThis->lighting != 0) {
1005 glDisable(GL_LIGHTING);
1006 glThis->lighting = 0;
1010 /* Handle the code for pre-vertex material properties */
1011 if (vertex_transformed == FALSE) {
1012 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1013 This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1014 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1015 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1016 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1017 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1018 glEnable(GL_COLOR_MATERIAL);
1025 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1026 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1028 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1030 switch (d3dvt) {
1031 case D3DVT_VERTEX: {
1032 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1033 strided.position.dwStride = sizeof(D3DVERTEX);
1034 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1035 strided.normal.dwStride = sizeof(D3DVERTEX);
1036 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1037 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1038 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1039 } break;
1041 case D3DVT_LVERTEX: {
1042 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1043 strided.position.dwStride = sizeof(D3DLVERTEX);
1044 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1045 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1046 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1047 strided.specular.dwStride = sizeof(D3DLVERTEX);
1048 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1049 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1050 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1051 } break;
1053 case D3DVT_TLVERTEX: {
1054 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1055 strided.position.dwStride = sizeof(D3DTLVERTEX);
1056 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1057 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1058 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1059 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1060 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1061 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1062 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1063 } break;
1065 default:
1066 FIXME("Unhandled vertex type %08x\n", d3dvt);
1067 break;
1071 HRESULT WINAPI
1072 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1073 D3DPRIMITIVETYPE d3dptPrimitiveType,
1074 D3DVERTEXTYPE d3dvtVertexType,
1075 LPVOID lpvVertices,
1076 DWORD dwVertexCount,
1077 DWORD dwFlags)
1079 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1081 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1082 if (TRACE_ON(ddraw)) {
1083 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1086 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1088 return DD_OK;
1091 HRESULT WINAPI
1092 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1093 D3DPRIMITIVETYPE d3dptPrimitiveType,
1094 D3DVERTEXTYPE d3dvtVertexType,
1095 LPVOID lpvVertices,
1096 DWORD dwVertexCount,
1097 LPWORD dwIndices,
1098 DWORD dwIndexCount,
1099 DWORD dwFlags)
1101 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1102 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1103 if (TRACE_ON(ddraw)) {
1104 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1107 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1109 return DD_OK;
1112 HRESULT WINAPI
1113 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1114 LPD3DEXECUTEBUFFERDESC lpDesc,
1115 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1116 IUnknown* pUnkOuter)
1118 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1119 IDirect3DExecuteBufferImpl *ret;
1120 HRESULT ret_value;
1122 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1124 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1125 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1127 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1129 return ret_value;
1132 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1133 static BOOLEAN first = TRUE;
1134 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1135 unsigned int row;
1136 GLenum type;
1138 if (first) {
1139 MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1140 first = FALSE;
1143 TRACE("flushing ZBuffer back to GL\n");
1145 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1146 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1147 d3ddevice_set_ortho(d3d_dev);
1150 glMatrixMode(GL_MODELVIEW);
1151 glLoadIdentity();
1153 if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1154 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1155 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1157 /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1158 in some drivers...
1160 switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1161 case 16: type = GL_UNSIGNED_SHORT; break;
1162 case 32: type = GL_UNSIGNED_INT; break;
1163 default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1166 for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1167 /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1168 glRasterPos2i(0, row + 1);
1169 glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1170 ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1173 restore_state:
1174 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1175 if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1176 glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1177 if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1180 /* These are the various handler used in the generic path */
1181 inline static void handle_xyz(D3DVALUE *coords) {
1182 glVertex3fv(coords);
1184 inline static void handle_xyzrhw(D3DVALUE *coords) {
1185 if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1186 glVertex3fv(coords);
1187 else {
1188 GLfloat w = 1.0 / coords[3];
1190 glVertex4f(coords[0] * w,
1191 coords[1] * w,
1192 coords[2] * w,
1196 inline static void handle_normal(D3DVALUE *coords) {
1197 glNormal3fv(coords);
1200 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1201 if (sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] ||
1202 sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1]) {
1203 glColor4ub((*color >> 16) & 0xFF,
1204 (*color >> 8) & 0xFF,
1205 (*color >> 0) & 0xFF,
1206 (*color >> 24) & 0xFF);
1207 } else {
1208 glColor3ub((*color >> 16) & 0xFF,
1209 (*color >> 8) & 0xFF,
1210 (*color >> 0) & 0xFF);
1214 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1215 glColor4ub((*color >> 16) & 0xFF,
1216 (*color >> 8) & 0xFF,
1217 (*color >> 0) & 0xFF,
1218 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1221 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1222 if ((lighted == FALSE) &&
1223 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1224 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1225 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1226 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1227 handle_diffuse_base(sb, color);
1229 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1230 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1231 handle_diffuse_base(sb, color);
1233 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1234 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1235 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1236 handle_diffuse_base(sb, color);
1238 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1239 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1240 handle_diffuse_base(sb, color);
1242 } else {
1243 handle_diffuse_base(sb, color);
1247 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1248 if ((lighted == FALSE) &&
1249 sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1250 sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1251 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1252 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1253 handle_specular_base(sb, color);
1255 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1256 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1257 handle_specular_base(sb, color);
1259 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1260 sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1261 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1262 handle_specular_base(sb, color);
1264 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1265 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1266 handle_specular_base(sb, color);
1269 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1272 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1273 if (lighted) {
1274 DWORD color = *color_d;
1275 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
1276 /* Special case where the specular value is used to do fogging */
1277 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1278 color &= 0xFF000000; /* Only keep the alpha component */
1279 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1280 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1281 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1283 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1284 /* Standard specular value in transformed mode. TODO */
1286 handle_diffuse_base(sb, &color);
1287 } else {
1288 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1289 handle_diffuse(sb, color_d, FALSE);
1290 handle_specular(sb, color_s, FALSE);
1291 } else {
1292 /* In that case, only put the diffuse color... */
1293 handle_diffuse_base(sb, color_d);
1298 static void handle_texture(DWORD size, const D3DVALUE *coords) {
1299 switch (size) {
1300 case 1: glTexCoord1fv(coords); break;
1301 case 2: glTexCoord2fv(coords); break;
1302 case 3: glTexCoord3fv(coords); break;
1303 case 4: glTexCoord4fv(coords); break;
1307 inline static void handle_textures(DWORD size, const D3DVALUE *coords, int tex_stage) {
1308 if (GL_extensions.max_texture_units > 0) {
1309 GL_extensions.glMultiTexCoord[size - 1](GL_TEXTURE0_WINE + tex_stage, coords);
1310 } else {
1311 if (tex_stage == 0) handle_texture(size, coords);
1315 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1316 D3DPRIMITIVETYPE d3dptPrimitiveType,
1317 DWORD d3dvtVertexType,
1318 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1319 DWORD dwVertexCount,
1320 LPWORD dwIndices,
1321 DWORD dwIndexCount,
1322 DWORD dwFlags)
1324 BOOLEAN vertex_lighted = FALSE;
1325 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1326 int num_active_stages = 0;
1327 int num_tex_index = GET_TEXCOUNT_FROM_FVF(d3dvtVertexType);
1328 BOOL reenable_depth_test = FALSE;
1330 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1331 if (TRACE_ON(ddraw)) {
1332 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1335 /* This is to prevent 'thread contention' between a thread locking the device and another
1336 doing 3D display on it... */
1337 EnterCriticalSection(&(This->crit));
1339 ENTER_GL();
1340 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1341 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1343 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1345 if (This->current_zbuffer == NULL) {
1346 /* Search for an attached ZBuffer */
1347 static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1348 LPDIRECTDRAWSURFACE7 zbuf;
1349 HRESULT hr;
1351 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1352 (DDSCAPS2 *) &zbuf_caps, &zbuf);
1353 if (SUCCEEDED(hr)) {
1354 This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1355 IDirectDrawSurface7_Release(zbuf);
1356 } else if (glThis->depth_test) {
1357 glDisable(GL_DEPTH_TEST);
1358 reenable_depth_test = TRUE;
1361 if (This->current_zbuffer != NULL) {
1362 if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1363 flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1367 if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1368 ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1369 vertex_lighted = TRUE;
1371 /* Compute the number of active texture stages and set the various texture parameters */
1372 num_active_stages = draw_primitive_handle_textures(This);
1374 /* And restore to handle '0' in the case we use glTexCoord calls */
1375 if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1376 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1377 glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1380 draw_primitive_handle_GL_state(This,
1381 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1382 vertex_lighted);
1384 /* First, see if we can use the OpenGL vertex arrays... This is very limited
1385 for now to some 'special' cases where we can do a direct mapping between D3D
1386 types and GL types.
1388 Note: in the future all calls will go through vertex arrays but the arrays
1389 will be generated by this function.
1391 Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1392 (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1393 which, as we are little indian, gives a B, G, R, A storage in memory.
1395 if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1396 ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1397 int tex_stage;
1398 TRACE(" using GL vertex arrays for performance !\n");
1399 /* First, the vertices (we are sure we have some :-) */
1400 glEnableClientState(GL_VERTEX_ARRAY);
1401 glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1402 /* Then the normals */
1403 if (d3dvtVertexType & D3DFVF_NORMAL) {
1404 glEnableClientState(GL_NORMAL_ARRAY);
1405 glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1407 /* Then the diffuse colour */
1408 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1409 glEnableClientState(GL_COLOR_ARRAY);
1410 glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1411 ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1413 /* Then the various textures */
1414 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1415 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1416 if (tex_index >= num_tex_index) {
1417 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1418 tex_index = num_tex_index - 1;
1420 if (GL_extensions.glClientActiveTexture) {
1421 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1423 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1424 glTexCoordPointer(GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index), GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1425 lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1427 if (dwIndices != NULL) {
1428 glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1429 } else {
1430 glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1432 glDisableClientState(GL_VERTEX_ARRAY);
1433 if (d3dvtVertexType & D3DFVF_NORMAL) {
1434 glDisableClientState(GL_NORMAL_ARRAY);
1436 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1437 glDisableClientState(GL_COLOR_ARRAY);
1439 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1440 if (GL_extensions.glClientActiveTexture) {
1441 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1443 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1445 } else {
1446 glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1448 /* Some fast paths first before the generic case.... */
1449 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1450 unsigned int index;
1452 for (index = 0; index < dwIndexCount; index++) {
1453 int i = (dwIndices == NULL) ? index : dwIndices[index];
1454 D3DVALUE *normal =
1455 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1456 D3DVALUE *tex_coord =
1457 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1458 D3DVALUE *position =
1459 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1461 handle_normal(normal);
1462 handle_texture(2, tex_coord);
1463 handle_xyz(position);
1465 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1466 position[0], position[1], position[2],
1467 normal[0], normal[1], normal[2],
1468 tex_coord[0], tex_coord[1]);
1470 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1471 unsigned int index;
1473 for (index = 0; index < dwIndexCount; index++) {
1474 int i = (dwIndices == NULL) ? index : dwIndices[index];
1475 DWORD *color_d =
1476 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1477 DWORD *color_s =
1478 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1479 D3DVALUE *tex_coord =
1480 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1481 D3DVALUE *position =
1482 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1484 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1485 handle_texture(2, tex_coord);
1486 handle_xyzrhw(position);
1488 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1489 position[0], position[1], position[2], position[3],
1490 (*color_d >> 16) & 0xFF,
1491 (*color_d >> 8) & 0xFF,
1492 (*color_d >> 0) & 0xFF,
1493 (*color_d >> 24) & 0xFF,
1494 (*color_s >> 16) & 0xFF,
1495 (*color_s >> 8) & 0xFF,
1496 (*color_s >> 0) & 0xFF,
1497 (*color_s >> 24) & 0xFF,
1498 tex_coord[0], tex_coord[1]);
1500 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1501 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1502 /* This is the 'slow path' but that should support all possible vertex formats out there...
1503 Note that people should write a fast path for all vertex formats out there...
1505 unsigned int index;
1506 /* static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 }; */
1508 for (index = 0; index < dwIndexCount; index++) {
1509 int i = (dwIndices == NULL) ? index : dwIndices[index];
1510 int tex_stage;
1512 if (d3dvtVertexType & D3DFVF_NORMAL) {
1513 D3DVALUE *normal =
1514 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1515 handle_normal(normal);
1517 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1518 DWORD *color_d =
1519 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1520 DWORD *color_s =
1521 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1522 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1523 } else {
1524 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1525 DWORD *color_s =
1526 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1527 handle_specular(&(This->state_block), color_s, vertex_lighted);
1528 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1529 DWORD *color_d =
1530 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1531 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1535 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1536 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1537 D3DVALUE *tex_coord;
1539 if (tex_index >= num_tex_index) {
1540 /* This will have to be checked on Windows. RealMYST uses this feature and I would find it more
1541 * logical to re-use the index of the previous stage than a default index of '0'.
1544 /* handle_textures((const D3DVALUE *) no_index, tex_stage); */
1545 tex_index = num_tex_index - 1;
1547 tex_coord = (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1548 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1549 handle_textures(GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index), tex_coord, tex_stage);
1552 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1553 D3DVALUE *position =
1554 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1555 handle_xyz(position);
1556 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1557 D3DVALUE *position =
1558 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1559 handle_xyzrhw(position);
1562 if (TRACE_ON(ddraw_geom)) {
1563 unsigned int tex_index;
1565 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1566 D3DVALUE *position =
1567 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1568 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1569 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1570 D3DVALUE *position =
1571 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1572 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1574 if (d3dvtVertexType & D3DFVF_NORMAL) {
1575 D3DVALUE *normal =
1576 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1577 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1579 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1580 DWORD *color_d =
1581 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1582 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1583 (*color_d >> 16) & 0xFF,
1584 (*color_d >> 8) & 0xFF,
1585 (*color_d >> 0) & 0xFF,
1586 (*color_d >> 24) & 0xFF);
1588 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1589 DWORD *color_s =
1590 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1591 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1592 (*color_s >> 16) & 0xFF,
1593 (*color_s >> 8) & 0xFF,
1594 (*color_s >> 0) & 0xFF,
1595 (*color_s >> 24) & 0xFF);
1597 for (tex_index = 0; tex_index < GET_TEXCOUNT_FROM_FVF(d3dvtVertexType); tex_index++) {
1598 D3DVALUE *tex_coord =
1599 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1600 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1601 switch (GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index)) {
1602 case 1: TRACE_(ddraw_geom)(" / %f", tex_coord[0]); break;
1603 case 2: TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]); break;
1604 case 3: TRACE_(ddraw_geom)(" / %f %f %f", tex_coord[0], tex_coord[1], tex_coord[2]); break;
1605 case 4: TRACE_(ddraw_geom)(" / %f %f %f %f", tex_coord[0], tex_coord[1], tex_coord[2], tex_coord[3]); break;
1606 default: TRACE_(ddraw_geom)("Invalid texture size (%ld) !!!", GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index)); break;
1609 TRACE_(ddraw_geom)("\n");
1612 } else {
1613 ERR(" matrix weighting not handled yet....\n");
1616 glEnd();
1619 /* Whatever the case, disable the color material stuff */
1620 glDisable(GL_COLOR_MATERIAL);
1622 if (reenable_depth_test)
1623 glEnable(GL_DEPTH_TEST);
1625 LEAVE_GL();
1626 TRACE("End\n");
1628 LeaveCriticalSection(&(This->crit));
1631 HRESULT WINAPI
1632 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1633 D3DPRIMITIVETYPE d3dptPrimitiveType,
1634 DWORD d3dvtVertexType,
1635 LPVOID lpvVertices,
1636 DWORD dwVertexCount,
1637 DWORD dwFlags)
1639 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1640 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1642 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1643 if (TRACE_ON(ddraw)) {
1644 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1647 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1648 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1650 return DD_OK;
1653 HRESULT WINAPI
1654 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1655 D3DPRIMITIVETYPE d3dptPrimitiveType,
1656 DWORD d3dvtVertexType,
1657 LPVOID lpvVertices,
1658 DWORD dwVertexCount,
1659 LPWORD dwIndices,
1660 DWORD dwIndexCount,
1661 DWORD dwFlags)
1663 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1664 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1666 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1667 if (TRACE_ON(ddraw)) {
1668 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1671 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1672 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1674 return DD_OK;
1677 HRESULT WINAPI
1678 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1679 D3DPRIMITIVETYPE d3dptPrimitiveType,
1680 DWORD dwVertexType,
1681 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1682 DWORD dwVertexCount,
1683 DWORD dwFlags)
1685 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1687 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1688 if (TRACE_ON(ddraw)) {
1689 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1691 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1693 return DD_OK;
1696 HRESULT WINAPI
1697 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1698 D3DPRIMITIVETYPE d3dptPrimitiveType,
1699 DWORD dwVertexType,
1700 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1701 DWORD dwVertexCount,
1702 LPWORD lpIndex,
1703 DWORD dwIndexCount,
1704 DWORD dwFlags)
1706 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1708 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1709 if (TRACE_ON(ddraw)) {
1710 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1713 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1715 return DD_OK;
1718 HRESULT WINAPI
1719 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1720 D3DPRIMITIVETYPE d3dptPrimitiveType,
1721 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1722 DWORD dwStartVertex,
1723 DWORD dwNumVertices,
1724 DWORD dwFlags)
1726 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1727 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1728 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1730 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1731 if (TRACE_ON(ddraw)) {
1732 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1735 if (vb_impl->processed) {
1736 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1737 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1739 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1740 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1741 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1743 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1744 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1746 } else {
1747 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1748 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1751 return DD_OK;
1754 HRESULT WINAPI
1755 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1756 D3DPRIMITIVETYPE d3dptPrimitiveType,
1757 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1758 DWORD dwStartVertex,
1759 DWORD dwNumVertices,
1760 LPWORD lpwIndices,
1761 DWORD dwIndexCount,
1762 DWORD dwFlags)
1764 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1765 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1766 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1768 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1769 if (TRACE_ON(ddraw)) {
1770 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1773 if (vb_impl->processed) {
1774 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1775 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1777 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1778 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1779 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1781 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1782 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1784 } else {
1785 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1786 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1789 return DD_OK;
1792 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1793 static BOOLEAN
1794 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1796 BOOLEAN is_complement = FALSE;
1797 BOOLEAN is_alpha_replicate = FALSE;
1798 BOOLEAN handled = TRUE;
1799 GLenum src;
1800 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1801 int num;
1803 if (is_color) {
1804 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1805 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1806 else {
1807 handled = FALSE;
1808 num = 0;
1810 if (tex_op == D3DTOP_SELECTARG2) {
1811 num = 1 - num;
1813 } else {
1814 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1815 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1816 else {
1817 handled = FALSE;
1818 num = 0;
1820 if (tex_op == D3DTOP_SELECTARG2) {
1821 num = 1 - num;
1825 if (dwState & D3DTA_COMPLEMENT) {
1826 is_complement = TRUE;
1828 if (dwState & D3DTA_ALPHAREPLICATE) {
1829 is_alpha_replicate = TRUE;
1831 dwState &= D3DTA_SELECTMASK;
1832 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1833 dwState = D3DTA_DIFFUSE;
1836 switch (dwState) {
1837 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1838 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1839 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1840 case D3DTA_TFACTOR: {
1841 /* Get the constant value from the current rendering state */
1842 GLfloat color[4];
1843 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1845 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1846 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1847 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1848 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1849 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1851 src = GL_CONSTANT_EXT;
1852 } break;
1853 default: src = GL_TEXTURE; handled = FALSE; break;
1856 if (is_color) {
1857 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1858 if (is_alpha_replicate) {
1859 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1860 } else {
1861 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1863 } else {
1864 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1865 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1868 return handled;
1871 HRESULT WINAPI
1872 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1873 DWORD dwStage,
1874 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1875 DWORD dwState)
1877 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1878 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1879 const char *type;
1880 DWORD prev_state;
1881 GLenum unit;
1883 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1885 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1886 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1887 return DD_OK;
1890 unit = GL_TEXTURE0_WINE + dwStage;
1891 if (unit != glThis->current_active_tex_unit) {
1892 GL_extensions.glActiveTexture(unit);
1893 glThis->current_active_tex_unit = unit;
1896 switch (d3dTexStageStateType) {
1897 #define GEN_CASE(a) case a: type = #a; break
1898 GEN_CASE(D3DTSS_COLOROP);
1899 GEN_CASE(D3DTSS_COLORARG1);
1900 GEN_CASE(D3DTSS_COLORARG2);
1901 GEN_CASE(D3DTSS_ALPHAOP);
1902 GEN_CASE(D3DTSS_ALPHAARG1);
1903 GEN_CASE(D3DTSS_ALPHAARG2);
1904 GEN_CASE(D3DTSS_BUMPENVMAT00);
1905 GEN_CASE(D3DTSS_BUMPENVMAT01);
1906 GEN_CASE(D3DTSS_BUMPENVMAT10);
1907 GEN_CASE(D3DTSS_BUMPENVMAT11);
1908 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1909 GEN_CASE(D3DTSS_ADDRESS);
1910 GEN_CASE(D3DTSS_ADDRESSU);
1911 GEN_CASE(D3DTSS_ADDRESSV);
1912 GEN_CASE(D3DTSS_BORDERCOLOR);
1913 GEN_CASE(D3DTSS_MAGFILTER);
1914 GEN_CASE(D3DTSS_MINFILTER);
1915 GEN_CASE(D3DTSS_MIPFILTER);
1916 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1917 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1918 GEN_CASE(D3DTSS_MAXANISOTROPY);
1919 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1920 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1921 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1922 #undef GEN_CASE
1923 default: type = "UNKNOWN";
1926 /* Store the values in the state array */
1927 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1928 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1929 /* Some special cases when one state modifies more than one... */
1930 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1931 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1932 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1935 ENTER_GL();
1937 switch (d3dTexStageStateType) {
1938 case D3DTSS_MINFILTER:
1939 case D3DTSS_MIPFILTER:
1940 if (TRACE_ON(ddraw)) {
1941 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1942 switch ((D3DTEXTUREMINFILTER) dwState) {
1943 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1944 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1945 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1947 } else {
1948 switch ((D3DTEXTUREMIPFILTER) dwState) {
1949 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1950 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1951 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1952 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1956 break;
1958 case D3DTSS_MAGFILTER:
1959 if (TRACE_ON(ddraw)) {
1960 switch ((D3DTEXTUREMAGFILTER) dwState) {
1961 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1962 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1963 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1966 break;
1968 case D3DTSS_ADDRESS:
1969 case D3DTSS_ADDRESSU:
1970 case D3DTSS_ADDRESSV: {
1971 switch ((D3DTEXTUREADDRESS) dwState) {
1972 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1973 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1974 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1975 case D3DTADDRESS_MIRROR:
1976 if (GL_extensions.mirrored_repeat) {
1977 TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1978 } else {
1979 FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1981 break;
1982 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1984 } break;
1986 case D3DTSS_ALPHAOP:
1987 case D3DTSS_COLOROP: {
1988 int scale = 1;
1989 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1990 const char *value;
1991 int handled = 1;
1993 switch (dwState) {
1994 #define GEN_CASE(a) case a: value = #a; break
1995 GEN_CASE(D3DTOP_DISABLE);
1996 GEN_CASE(D3DTOP_SELECTARG1);
1997 GEN_CASE(D3DTOP_SELECTARG2);
1998 GEN_CASE(D3DTOP_MODULATE);
1999 GEN_CASE(D3DTOP_MODULATE2X);
2000 GEN_CASE(D3DTOP_MODULATE4X);
2001 GEN_CASE(D3DTOP_ADD);
2002 GEN_CASE(D3DTOP_ADDSIGNED);
2003 GEN_CASE(D3DTOP_ADDSIGNED2X);
2004 GEN_CASE(D3DTOP_SUBTRACT);
2005 GEN_CASE(D3DTOP_ADDSMOOTH);
2006 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
2007 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
2008 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
2009 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
2010 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
2011 GEN_CASE(D3DTOP_PREMODULATE);
2012 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
2013 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
2014 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
2015 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
2016 GEN_CASE(D3DTOP_BUMPENVMAP);
2017 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
2018 GEN_CASE(D3DTOP_DOTPRODUCT3);
2019 GEN_CASE(D3DTOP_FORCE_DWORD);
2020 #undef GEN_CASE
2021 default: value = "UNKNOWN";
2024 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
2025 glDisable(GL_TEXTURE_2D);
2026 TRACE(" disabling 2D texturing.\n");
2027 } else {
2028 /* Re-enable texturing only if COLOROP was not already disabled... */
2029 if ((glThis->current_bound_texture[dwStage] != NULL) &&
2030 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2031 glEnable(GL_TEXTURE_2D);
2032 TRACE(" enabling 2D texturing.\n");
2035 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2036 if ((dwState != D3DTOP_DISABLE) &&
2037 (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2038 if (glThis->current_tex_env != GL_COMBINE_EXT) {
2039 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2040 glThis->current_tex_env = GL_COMBINE_EXT;
2044 /* Now set up the operand correctly */
2045 switch (dwState) {
2046 case D3DTOP_DISABLE:
2047 /* Contrary to the docs, alpha can be disabled when colorop is enabled
2048 and it works, so ignore this op */
2049 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2050 break;
2052 case D3DTOP_SELECTARG1:
2053 case D3DTOP_SELECTARG2:
2054 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2055 break;
2057 case D3DTOP_MODULATE4X:
2058 scale = scale * 2; /* Drop through */
2059 case D3DTOP_MODULATE2X:
2060 scale = scale * 2; /* Drop through */
2061 case D3DTOP_MODULATE:
2062 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2063 break;
2065 case D3DTOP_ADD:
2066 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2067 break;
2069 case D3DTOP_ADDSIGNED2X:
2070 scale = scale * 2; /* Drop through */
2071 case D3DTOP_ADDSIGNED:
2072 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2073 break;
2075 /* For the four blending modes, use the Arg2 parameter */
2076 case D3DTOP_BLENDDIFFUSEALPHA:
2077 case D3DTOP_BLENDTEXTUREALPHA:
2078 case D3DTOP_BLENDFACTORALPHA:
2079 case D3DTOP_BLENDCURRENTALPHA: {
2080 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2082 switch (dwState) {
2083 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2084 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2085 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
2086 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2089 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2090 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2091 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2092 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2093 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2094 } break;
2096 default:
2097 handled = FALSE;
2098 break;
2102 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2103 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2104 /* Switch the arguments if needed... */
2105 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2106 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2107 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2108 dwState);
2109 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2110 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2111 dwState);
2112 } else {
2113 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2114 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2115 dwState);
2116 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2117 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2118 dwState);
2122 if (handled) {
2123 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2124 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2125 } else {
2126 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2128 TRACE(" Stage type is : %s => %s\n", type, value);
2129 } else {
2130 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2132 } break;
2134 case D3DTSS_COLORARG1:
2135 case D3DTSS_COLORARG2:
2136 case D3DTSS_ALPHAARG1:
2137 case D3DTSS_ALPHAARG2: {
2138 const char *value, *value_comp = "", *value_alpha = "";
2139 BOOLEAN handled;
2140 D3DTEXTUREOP tex_op;
2142 switch (dwState & D3DTA_SELECTMASK) {
2143 #define GEN_CASE(a) case a: value = #a; break
2144 GEN_CASE(D3DTA_DIFFUSE);
2145 GEN_CASE(D3DTA_CURRENT);
2146 GEN_CASE(D3DTA_TEXTURE);
2147 GEN_CASE(D3DTA_TFACTOR);
2148 GEN_CASE(D3DTA_SPECULAR);
2149 #undef GEN_CASE
2150 default: value = "UNKNOWN";
2152 if (dwState & D3DTA_COMPLEMENT) {
2153 value_comp = " | D3DTA_COMPLEMENT";
2155 if (dwState & D3DTA_ALPHAREPLICATE) {
2156 value_alpha = " | D3DTA_ALPHAREPLICATE";
2159 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2160 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2161 } else {
2162 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2165 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2167 if (handled) {
2168 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2169 } else {
2170 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2172 } break;
2174 case D3DTSS_MIPMAPLODBIAS: {
2175 D3DVALUE value = *((D3DVALUE *) &dwState);
2176 BOOLEAN handled = TRUE;
2178 if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2179 handled = FALSE;
2181 if (handled) {
2182 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2183 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2184 } else {
2185 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2187 } break;
2189 case D3DTSS_MAXMIPLEVEL:
2190 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2191 break;
2193 case D3DTSS_BORDERCOLOR:
2194 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2195 ((dwState >> 16) & 0xFF),
2196 ((dwState >> 8) & 0xFF),
2197 ((dwState >> 0) & 0xFF),
2198 ((dwState >> 24) & 0xFF));
2199 break;
2201 case D3DTSS_TEXCOORDINDEX: {
2202 BOOLEAN handled = TRUE;
2203 const char *value;
2205 switch (dwState & 0xFFFF0000) {
2206 #define GEN_CASE(a) case a: value = #a; break
2207 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2208 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2209 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2210 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2211 #undef GEN_CASE
2212 default: value = "UNKNOWN";
2214 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2215 handled = FALSE;
2217 if (handled) {
2218 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2219 } else {
2220 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2222 } break;
2224 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2225 const char *projected = "", *value;
2226 BOOLEAN handled = TRUE;
2227 switch (dwState & 0xFF) {
2228 #define GEN_CASE(a) case a: value = #a; break
2229 GEN_CASE(D3DTTFF_DISABLE);
2230 GEN_CASE(D3DTTFF_COUNT1);
2231 GEN_CASE(D3DTTFF_COUNT2);
2232 GEN_CASE(D3DTTFF_COUNT3);
2233 GEN_CASE(D3DTTFF_COUNT4);
2234 #undef GEN_CASE
2235 default: value = "UNKNOWN";
2237 if (dwState & D3DTTFF_PROJECTED) {
2238 projected = " | D3DTTFF_PROJECTED";
2239 handled = FALSE;
2242 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2243 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2246 if (handled) {
2247 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2248 } else {
2249 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2251 } break;
2253 default:
2254 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2255 break;
2258 LEAVE_GL();
2260 return DD_OK;
2263 static DWORD
2264 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2266 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2267 DWORD stage;
2268 BOOLEAN enable_colorkey = FALSE;
2270 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2271 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2272 GLenum unit;
2274 /* If this stage is disabled, no need to go further... */
2275 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2276 break;
2278 /* First check if we need to bind any other texture for this stage */
2279 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2280 if (This->current_texture[stage] == NULL) {
2281 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2283 unit = GL_TEXTURE0_WINE + stage;
2284 if (unit != glThis->current_active_tex_unit) {
2285 GL_extensions.glActiveTexture(unit);
2286 glThis->current_active_tex_unit = unit;
2288 glBindTexture(GL_TEXTURE_2D, 0);
2289 glDisable(GL_TEXTURE_2D);
2290 } else {
2291 GLenum tex_name = gltex_get_tex_name(surf_ptr);
2293 unit = GL_TEXTURE0_WINE + stage;
2294 if (unit != glThis->current_active_tex_unit) {
2295 GL_extensions.glActiveTexture(unit);
2296 glThis->current_active_tex_unit = unit;
2299 if (glThis->current_bound_texture[stage] == NULL) {
2300 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2301 TRACE(" enabling 2D texturing and");
2302 glEnable(GL_TEXTURE_2D);
2305 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2306 glBindTexture(GL_TEXTURE_2D, tex_name);
2309 glThis->current_bound_texture[stage] = This->current_texture[stage];
2310 } else {
2311 if (glThis->current_bound_texture[stage] == NULL) {
2312 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2313 } else {
2314 TRACE(" using already bound texture id %d for stage %ld.\n",
2315 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2319 /* If no texure valid for this stage, go out of the loop */
2320 if (This->current_texture[stage] == NULL) break;
2322 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2323 This will also update the various texture parameters if needed.
2325 gltex_upload_texture(surf_ptr, This, stage);
2327 /* And finally check for color-keying (only on first stage) */
2328 if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2329 if (stage == 0) {
2330 enable_colorkey = TRUE;
2331 } else {
2332 static BOOL warn = FALSE;
2333 if (warn == FALSE) {
2334 warn = TRUE;
2335 WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2338 } else {
2339 if (stage == 0) {
2340 enable_colorkey = FALSE;
2345 /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2346 if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2347 (glThis->parent.version == 1)) &&
2348 (enable_colorkey)) {
2349 TRACE(" colorkey activated.\n");
2351 if (glThis->alpha_test == FALSE) {
2352 glEnable(GL_ALPHA_TEST);
2353 glThis->alpha_test = TRUE;
2355 if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2356 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1]) {
2357 static BOOL warn = FALSE;
2358 if (warn == FALSE) {
2359 warn = TRUE;
2360 WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2363 glThis->current_alpha_test_func = GL_NOTEQUAL;
2364 glThis->current_alpha_test_ref = 0.0;
2365 glAlphaFunc(GL_NOTEQUAL, 0.0);
2367 /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2368 Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2369 } else {
2370 if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2371 glDisable(GL_ALPHA_TEST);
2372 glThis->alpha_test = FALSE;
2374 /* Maybe we should restore here the application-given alpha test states ? */
2377 return stage;
2380 HRESULT WINAPI
2381 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2382 DWORD dwStage,
2383 LPDIRECTDRAWSURFACE7 lpTexture2)
2385 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2387 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2389 if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2390 ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2391 if (lpTexture2 != NULL) {
2392 WARN(" setting a texture to a non-supported texture stage !\n");
2394 return DD_OK;
2397 if (This->current_texture[dwStage] != NULL) {
2398 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2401 if (lpTexture2 == NULL) {
2402 This->current_texture[dwStage] = NULL;
2403 } else {
2404 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2405 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2406 This->current_texture[dwStage] = tex_impl;
2409 return DD_OK;
2412 static HRESULT WINAPI
2413 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2414 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2416 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2417 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2419 fill_opengl_caps_7(lpD3DHELDevDesc);
2421 TRACE(" returning caps : no dump function yet.\n");
2423 return DD_OK;
2426 HRESULT WINAPI
2427 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2428 LPD3DMATERIAL7 lpMat)
2430 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2431 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2433 if (TRACE_ON(ddraw)) {
2434 TRACE(" material is : \n");
2435 dump_D3DMATERIAL7(lpMat);
2438 This->current_material = *lpMat;
2440 ENTER_GL();
2441 glMaterialfv(GL_FRONT_AND_BACK,
2442 GL_DIFFUSE,
2443 (float *) &(This->current_material.u.diffuse));
2444 glMaterialfv(GL_FRONT_AND_BACK,
2445 GL_AMBIENT,
2446 (float *) &(This->current_material.u1.ambient));
2447 glMaterialfv(GL_FRONT_AND_BACK,
2448 GL_SPECULAR,
2449 (float *) &(This->current_material.u2.specular));
2450 glMaterialfv(GL_FRONT_AND_BACK,
2451 GL_EMISSION,
2452 (float *) &(This->current_material.u3.emissive));
2453 glMaterialf(GL_FRONT_AND_BACK,
2454 GL_SHININESS,
2455 This->current_material.u4.power); /* Not sure about this... */
2456 LEAVE_GL();
2458 return DD_OK;
2461 static LPD3DLIGHT7 get_light(IDirect3DDeviceImpl *This, DWORD dwLightIndex)
2463 if (dwLightIndex >= This->num_set_lights)
2465 /* Extend, or allocate the light parameters array. */
2466 DWORD newlightnum = dwLightIndex + 1;
2467 LPD3DLIGHT7 newarrayptr = NULL;
2469 if (This->light_parameters)
2470 newarrayptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2471 This->light_parameters, newlightnum * sizeof(D3DLIGHT7));
2472 else
2473 newarrayptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2474 newlightnum * sizeof(D3DLIGHT7));
2476 if (!newarrayptr)
2477 return NULL;
2479 This->light_parameters = newarrayptr;
2480 This->num_set_lights = newlightnum;
2483 return &This->light_parameters[dwLightIndex];
2486 HRESULT WINAPI
2487 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2488 DWORD dwLightIndex,
2489 LPD3DLIGHT7 lpLight)
2491 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2492 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2493 LPD3DLIGHT7 lpdestlight = get_light( This, dwLightIndex );
2495 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2497 if (TRACE_ON(ddraw)) {
2498 TRACE(" setting light : \n");
2499 dump_D3DLIGHT7(lpLight);
2502 /* DirectX7 documentation states that this function can return
2503 DDERR_OUTOFMEMORY, so we do just that in case of an allocation
2504 error (which is the only reason why get_light() can fail). */
2505 if( !lpdestlight )
2506 return DDERR_OUTOFMEMORY;
2508 *lpdestlight = *lpLight;
2510 /* Some checks to print out nice warnings :-) */
2511 switch (lpLight->dltType) {
2512 case D3DLIGHT_DIRECTIONAL:
2513 case D3DLIGHT_POINT:
2514 /* These are handled properly... */
2515 break;
2517 case D3DLIGHT_SPOT:
2518 if ((lpLight->dvTheta != 0.0) ||
2519 (lpLight->dvTheta != lpLight->dvPhi)) {
2520 ERR("dvTheta not fully supported yet !\n");
2522 break;
2524 default:
2525 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2528 /* This will force the Light setting on next drawing of primitives */
2529 glThis->transform_state = GL_TRANSFORM_NONE;
2531 return DD_OK;
2534 HRESULT WINAPI
2535 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2536 DWORD dwLightIndex,
2537 BOOL bEnable)
2539 int lightslot = -1, i;
2540 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2541 LPD3DLIGHT7 lpdestlight = get_light(This, dwLightIndex);
2543 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2545 /* The DirectX doc isn't as explicit as for SetLight as whether we can
2546 return this from this function, but it doesn't state otherwise. */
2547 if (!lpdestlight)
2548 return DDERR_OUTOFMEMORY;
2550 /* If this light hasn't been set, initialise it with default values. */
2551 if (lpdestlight->dltType == 0)
2553 TRACE("setting default light parameters\n");
2555 /* We always use HEAP_ZERO_MEMORY when allocating the light_parameters
2556 array, so we only have to setup anything that shoud not be zero. */
2557 lpdestlight->dltType = D3DLIGHT_DIRECTIONAL;
2558 lpdestlight->dcvDiffuse.u1.r = 1.f;
2559 lpdestlight->dcvDiffuse.u2.g = 1.f;
2560 lpdestlight->dcvDiffuse.u3.b = 1.f;
2561 lpdestlight->dvDirection.u3.z = 1.f;
2564 /* Look for this light in the active lights array. */
2565 for (i = 0; i < This->max_active_lights; i++)
2566 if (This->active_lights[i] == dwLightIndex)
2568 lightslot = i;
2569 break;
2572 /* If we didn't find it, let's find the first available slot, if any. */
2573 if (lightslot == -1)
2574 for (i = 0; i < This->max_active_lights; i++)
2575 if (This->active_lights[i] == ~0)
2577 lightslot = i;
2578 break;
2581 ENTER_GL();
2582 if (bEnable) {
2583 if (lightslot == -1)
2585 /* This means that the app is trying to enable more lights than
2586 the maximum possible indicated in the caps.
2588 Windows actually let you do this, and disable one of the
2589 previously enabled lights to let you enable this one.
2591 It's not documented and I'm not sure how windows pick which light
2592 to disable to make room for this one. */
2593 FIXME("Enabling more light than the maximum is not supported yet.");
2594 return D3D_OK;
2597 glEnable(GL_LIGHT0 + lightslot);
2600 if (This->active_lights[lightslot] == ~0)
2602 /* This light gets active... Need to update its parameters to GL before the next drawing */
2603 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2605 This->active_lights[lightslot] = dwLightIndex;
2606 glThis->transform_state = GL_TRANSFORM_NONE;
2608 } else {
2609 glDisable(GL_LIGHT0 + lightslot);
2610 This->active_lights[lightslot] = ~0;
2613 LEAVE_GL();
2614 return DD_OK;
2617 HRESULT WINAPI
2618 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2620 IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2621 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2623 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2625 if (dwIndex >= This->max_clipping_planes) {
2626 return DDERR_INVALIDPARAMS;
2629 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2631 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2633 /* This is to force the reset of the transformation matrices on the next drawing.
2634 * This is needed to use the correct matrices for the various clipping planes.
2636 glThis->transform_state = GL_TRANSFORM_NONE;
2638 return D3D_OK;
2641 static HRESULT WINAPI
2642 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2643 LPD3DVIEWPORT7 lpData)
2645 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2646 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2648 if (TRACE_ON(ddraw)) {
2649 TRACE(" viewport is : \n");
2650 TRACE(" - dwX = %ld dwY = %ld\n",
2651 lpData->dwX, lpData->dwY);
2652 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2653 lpData->dwWidth, lpData->dwHeight);
2654 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2655 lpData->dvMinZ, lpData->dvMaxZ);
2657 ENTER_GL();
2659 /* Set the viewport */
2660 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2661 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2662 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2664 if ((lpData->dwX != This->active_viewport.dwX) ||
2665 (lpData->dwY != This->active_viewport.dwY) ||
2666 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2667 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2668 glViewport(lpData->dwX,
2669 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2670 lpData->dwWidth, lpData->dwHeight);
2673 LEAVE_GL();
2675 This->active_viewport = *lpData;
2677 return DD_OK;
2680 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2681 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2682 #else
2683 # define XCAST(fun) (void*)
2684 #endif
2686 static const IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2688 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2689 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2690 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2691 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2692 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2693 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2694 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2695 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2696 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2697 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2698 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2699 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2700 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2701 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2702 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2703 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2704 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2705 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2706 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2707 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2708 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2709 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2710 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2711 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2712 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2713 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2714 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2715 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2716 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2717 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2718 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2719 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2720 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2721 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2722 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2723 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2724 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2725 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2726 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2727 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2728 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2729 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2730 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2731 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2732 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2733 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2734 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2735 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2736 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2739 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2740 #undef XCAST
2741 #endif
2744 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2745 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2746 #else
2747 # define XCAST(fun) (void*)
2748 #endif
2750 static const IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2752 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2753 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2754 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2755 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2756 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2757 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2758 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2759 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2760 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2761 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2762 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2763 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2764 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2765 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2766 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2767 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2768 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2769 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2770 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2771 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2772 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2773 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2774 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2775 XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2776 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2777 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2778 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2779 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2780 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2781 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2782 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2783 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2784 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2785 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2786 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2787 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2788 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2789 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2790 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2791 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2792 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2793 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2796 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2797 #undef XCAST
2798 #endif
2801 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2802 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2803 #else
2804 # define XCAST(fun) (void*)
2805 #endif
2807 static const IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2809 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2810 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2811 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2812 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2813 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2814 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2815 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2816 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2817 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2818 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2819 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2820 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2821 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2822 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2823 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2824 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2825 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2826 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2827 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2828 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2829 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2830 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2831 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2832 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2833 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2834 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2835 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2836 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2837 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2838 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2839 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2840 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2841 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2844 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2845 #undef XCAST
2846 #endif
2849 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2850 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2851 #else
2852 # define XCAST(fun) (void*)
2853 #endif
2855 static const IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2857 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2858 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2859 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2860 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2861 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2862 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2863 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2864 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2865 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2866 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2867 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2868 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2869 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2870 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2871 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2872 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2873 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2874 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2875 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2876 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2877 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2878 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2881 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2882 #undef XCAST
2883 #endif
2885 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2886 WINE_GL_BUFFER_TYPE buffer_type,
2887 DWORD dwCount,
2888 LPD3DRECT lpRects,
2889 DWORD dwFlags,
2890 DWORD dwColor,
2891 D3DVALUE dvZ,
2892 DWORD dwStencil)
2894 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2895 GLbitfield bitfield = 0;
2896 D3DRECT rect;
2897 unsigned int i;
2899 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2900 if (TRACE_ON(ddraw)) {
2901 if (dwCount > 0) {
2902 unsigned int i;
2903 TRACE(" rectangles : \n");
2904 for (i = 0; i < dwCount; i++) {
2905 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2910 if (dwCount == 0) {
2911 dwCount = 1;
2912 rect.u1.x1 = 0;
2913 rect.u2.y1 = 0;
2914 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2915 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2916 lpRects = &rect;
2919 /* Clears the screen */
2920 ENTER_GL();
2922 if (dwFlags & D3DCLEAR_TARGET) {
2923 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2924 /* TODO: optimize here the case where Clear changes all the screen... */
2925 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2927 glThis->state[buffer_type] = SURFACE_GL;
2930 if (dwFlags & D3DCLEAR_ZBUFFER) {
2931 bitfield |= GL_DEPTH_BUFFER_BIT;
2932 if (glThis->depth_mask == FALSE) {
2933 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2935 if (dvZ != glThis->prev_clear_Z) {
2936 glClearDepth(dvZ);
2937 glThis->prev_clear_Z = dvZ;
2939 TRACE(" depth value : %f\n", dvZ);
2941 if (dwFlags & D3DCLEAR_STENCIL) {
2942 bitfield |= GL_STENCIL_BUFFER_BIT;
2943 if (dwStencil != glThis->prev_clear_stencil) {
2944 glClearStencil(dwStencil);
2945 glThis->prev_clear_stencil = dwStencil;
2947 TRACE(" stencil value : %ld\n", dwStencil);
2949 if (dwFlags & D3DCLEAR_TARGET) {
2950 bitfield |= GL_COLOR_BUFFER_BIT;
2951 if (dwColor != glThis->prev_clear_color) {
2952 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2953 ((dwColor >> 8) & 0xFF) / 255.0,
2954 ((dwColor >> 0) & 0xFF) / 255.0,
2955 ((dwColor >> 24) & 0xFF) / 255.0);
2956 glThis->prev_clear_color = dwColor;
2958 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2961 glEnable(GL_SCISSOR_TEST);
2962 for (i = 0; i < dwCount; i++) {
2963 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2964 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2965 glClear(bitfield);
2967 glDisable(GL_SCISSOR_TEST);
2969 if (dwFlags & D3DCLEAR_ZBUFFER) {
2970 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2973 LEAVE_GL();
2975 return DD_OK;
2978 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2979 DWORD dwCount,
2980 LPD3DRECT lpRects,
2981 DWORD dwFlags,
2982 DWORD dwColor,
2983 D3DVALUE dvZ,
2984 DWORD dwStencil)
2986 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2989 static HRESULT
2990 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2991 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2993 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2994 WINE_GL_BUFFER_TYPE buffer_type;
2996 /* First check if we BLT to the backbuffer... */
2997 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2998 buffer_type = WINE_GL_BUFFER_BACK;
2999 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3000 buffer_type = WINE_GL_BUFFER_FRONT;
3001 } else {
3002 ERR("Only BLT override to front or back-buffer is supported for now !\n");
3003 return DDERR_INVALIDPARAMS;
3006 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
3007 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
3008 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
3009 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
3010 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3011 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
3012 * GL to do it.
3014 return DDERR_INVALIDPARAMS;
3016 *buffer_type_p = buffer_type;
3018 return DD_OK;
3021 HRESULT
3022 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
3023 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
3024 DWORD dwFlags, LPDDBLTFX lpbltfx)
3026 WINE_GL_BUFFER_TYPE buffer_type;
3027 D3DRECT rect;
3029 if (rdst) {
3030 rect.u1.x1 = rdst->left;
3031 rect.u2.y1 = rdst->top;
3032 rect.u3.x2 = rdst->right;
3033 rect.u4.y2 = rdst->bottom;
3034 } else {
3035 rect.u1.x1 = 0;
3036 rect.u2.y1 = 0;
3037 rect.u3.x2 = This->surface_desc.dwWidth;
3038 rect.u4.y2 = This->surface_desc.dwHeight;
3041 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
3043 if (dwFlags & DDBLT_COLORFILL) {
3044 /* This is easy to handle for the D3D Device... */
3045 DWORD color;
3046 GLint prev_draw;
3048 /* The color as given in the Blt function is in the format of the frame-buffer...
3049 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3051 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
3052 if (This->palette) {
3053 color = ((0xFF000000) |
3054 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
3055 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
3056 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
3057 } else {
3058 color = 0xFF000000;
3060 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
3061 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3062 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3063 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3064 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3065 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3066 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3067 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
3068 color = 0xFFFFFFFF;
3069 } else {
3070 color = ((0xFF000000) |
3071 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
3072 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
3073 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
3075 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
3076 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
3077 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3078 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3079 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3080 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
3081 } else {
3082 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
3083 return DDERR_INVALIDPARAMS;
3085 } else {
3086 ERR("Wrong surface type for BLT override !\n");
3087 return DDERR_INVALIDPARAMS;
3090 TRACE(" executing D3D Device override.\n");
3092 ENTER_GL();
3094 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3095 if (buffer_type == WINE_GL_BUFFER_FRONT)
3096 glDrawBuffer(GL_FRONT);
3097 else
3098 glDrawBuffer(GL_BACK);
3100 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
3102 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3103 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3104 glDrawBuffer(prev_draw);
3106 LEAVE_GL();
3108 return DD_OK;
3109 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
3110 /* Normal blit without any special case... */
3111 if (src != NULL) {
3112 /* And which has a SRC surface */
3113 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3115 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3116 (src_impl->d3ddevice == This->d3ddevice) &&
3117 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3118 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3119 D3DRECT src_rect;
3120 int width, height;
3121 GLint prev_draw;
3122 WINE_GL_BUFFER_TYPE src_buffer_type;
3123 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3124 BOOLEAN initial;
3125 DWORD opt_bitmap;
3126 int x, y;
3128 if (rsrc) {
3129 src_rect.u1.x1 = rsrc->left;
3130 src_rect.u2.y1 = rsrc->top;
3131 src_rect.u3.x2 = rsrc->right;
3132 src_rect.u4.y2 = rsrc->bottom;
3133 } else {
3134 src_rect.u1.x1 = 0;
3135 src_rect.u2.y1 = 0;
3136 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3137 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3140 width = src_rect.u3.x2 - src_rect.u1.x1;
3141 height = src_rect.u4.y2 - src_rect.u2.y1;
3143 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3144 (height != (rect.u4.y2 - rect.u2.y1))) {
3145 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3146 return DDERR_INVALIDPARAMS;
3149 /* First check if we BLT from the backbuffer... */
3150 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3151 src_buffer_type = WINE_GL_BUFFER_BACK;
3152 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3153 src_buffer_type = WINE_GL_BUFFER_FRONT;
3154 } else {
3155 ERR("Unexpected case in direct buffer to buffer copy !\n");
3156 return DDERR_INVALIDPARAMS;
3159 TRACE(" using direct buffer to buffer copy.\n");
3161 ENTER_GL();
3163 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3165 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3166 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3167 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3168 LEAVE_GL();
3169 return DDERR_INVALIDPARAMS;
3172 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3173 if (buffer_type == WINE_GL_BUFFER_FRONT)
3174 glDrawBuffer(GL_FRONT);
3175 else
3176 glDrawBuffer(GL_BACK);
3178 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3179 glReadBuffer(GL_FRONT);
3180 else
3181 glReadBuffer(GL_BACK);
3183 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3184 And directly re-draws this on the destination buffer. */
3185 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3186 int get_height;
3188 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3189 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3190 else
3191 get_height = UNLOCK_TEX_SIZE;
3193 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3194 int get_width;
3196 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3197 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3198 else
3199 get_width = UNLOCK_TEX_SIZE;
3201 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3202 0, UNLOCK_TEX_SIZE - get_height,
3203 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3204 get_width, get_height);
3206 glBegin(GL_QUADS);
3207 glTexCoord2f(0.0, 0.0);
3208 glVertex3d(rect.u1.x1 + x,
3209 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3210 0.5);
3211 glTexCoord2f(1.0, 0.0);
3212 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3213 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3214 0.5);
3215 glTexCoord2f(1.0, 1.0);
3216 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3217 rect.u2.y1 + y,
3218 0.5);
3219 glTexCoord2f(0.0, 1.0);
3220 glVertex3d(rect.u1.x1 + x,
3221 rect.u2.y1 + y,
3222 0.5);
3223 glEnd();
3227 upload_surface_to_tex_memory_release();
3228 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3230 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3231 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3232 glDrawBuffer(prev_draw);
3234 LEAVE_GL();
3236 return DD_OK;
3237 } else {
3238 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3239 (this prevents calling glReadPixels) */
3240 D3DRECT src_rect;
3241 int width, height;
3242 GLint prev_draw;
3243 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3244 BOOLEAN initial;
3245 DWORD opt_bitmap;
3246 int x, y;
3247 double x_stretch, y_stretch;
3249 if (rsrc) {
3250 src_rect.u1.x1 = rsrc->left;
3251 src_rect.u2.y1 = rsrc->top;
3252 src_rect.u3.x2 = rsrc->right;
3253 src_rect.u4.y2 = rsrc->bottom;
3254 } else {
3255 src_rect.u1.x1 = 0;
3256 src_rect.u2.y1 = 0;
3257 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3258 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3261 width = src_rect.u3.x2 - src_rect.u1.x1;
3262 height = src_rect.u4.y2 - src_rect.u2.y1;
3264 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3265 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3267 TRACE(" using memory to buffer Blt override.\n");
3269 ENTER_GL();
3271 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3273 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3274 initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3275 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3276 LEAVE_GL();
3277 return DDERR_INVALIDPARAMS;
3280 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3281 if (buffer_type == WINE_GL_BUFFER_FRONT)
3282 glDrawBuffer(GL_FRONT);
3283 else
3284 glDrawBuffer(GL_BACK);
3286 /* Now the serious stuff happens. This is basically the same code as for the memory
3287 flush to frame buffer ... with stretching and different rectangles added :-) */
3288 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3289 RECT flush_rect;
3291 flush_rect.top = src_rect.u2.y1 + y;
3292 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3293 src_rect.u4.y2 :
3294 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3296 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3297 flush_rect.left = src_rect.u1.x1 + x;
3298 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3299 src_rect.u3.x2 :
3300 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3302 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3304 glBegin(GL_QUADS);
3305 glTexCoord2f(0.0, 0.0);
3306 glVertex3d(rect.u1.x1 + (x * x_stretch),
3307 rect.u2.y1 + (y * y_stretch),
3308 0.5);
3309 glTexCoord2f(1.0, 0.0);
3310 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3311 rect.u2.y1 + (y * y_stretch),
3312 0.5);
3313 glTexCoord2f(1.0, 1.0);
3314 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3315 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3316 0.5);
3317 glTexCoord2f(0.0, 1.0);
3318 glVertex3d(rect.u1.x1 + (x * x_stretch),
3319 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3320 0.5);
3321 glEnd();
3325 upload_surface_to_tex_memory_release();
3326 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3328 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3329 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3330 glDrawBuffer(prev_draw);
3332 LEAVE_GL();
3334 return DD_OK;
3338 return DDERR_INVALIDPARAMS;
3341 HRESULT
3342 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3343 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3344 LPRECT rsrc, DWORD trans)
3346 RECT rsrc2;
3347 RECT rdst;
3348 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3349 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3350 WINE_GL_BUFFER_TYPE buffer_type;
3351 GLint prev_draw;
3352 DWORD opt_bitmap;
3353 BOOLEAN initial;
3354 int width, height, x, y;
3356 /* Cannot support DSTCOLORKEY blitting... */
3357 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3359 if (rsrc == NULL) {
3360 WARN("rsrc is NULL - getting the whole surface !!\n");
3361 rsrc = &rsrc2;
3362 rsrc->left = rsrc->top = 0;
3363 rsrc->right = src_impl->surface_desc.dwWidth;
3364 rsrc->bottom = src_impl->surface_desc.dwHeight;
3365 } else {
3366 rsrc2 = *rsrc;
3367 rsrc = &rsrc2;
3370 rdst.left = dstx;
3371 rdst.top = dsty;
3372 rdst.right = dstx + (rsrc->right - rsrc->left);
3373 if (rdst.right > This->surface_desc.dwWidth) {
3374 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3375 rdst.right = This->surface_desc.dwWidth;
3377 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3378 if (rdst.bottom > This->surface_desc.dwHeight) {
3379 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3380 rdst.bottom = This->surface_desc.dwHeight;
3383 width = rsrc->right - rsrc->left;
3384 height = rsrc->bottom - rsrc->top;
3386 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3388 TRACE(" using BltFast memory to frame buffer override.\n");
3390 ENTER_GL();
3392 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3394 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3395 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3396 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3397 ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3398 LEAVE_GL();
3399 return DDERR_INVALIDPARAMS;
3402 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3403 if (buffer_type == WINE_GL_BUFFER_FRONT)
3404 glDrawBuffer(GL_FRONT);
3405 else
3406 glDrawBuffer(GL_BACK);
3408 /* Now the serious stuff happens. This is basically the same code that for the memory
3409 flush to frame buffer but with different rectangles for source and destination :-) */
3410 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3411 RECT flush_rect;
3413 flush_rect.top = rsrc->top + y;
3414 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3415 rsrc->bottom :
3416 (rsrc->top + y + UNLOCK_TEX_SIZE));
3418 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3419 flush_rect.left = rsrc->left + x;
3420 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3421 rsrc->right :
3422 (rsrc->left + x + UNLOCK_TEX_SIZE));
3424 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3426 glBegin(GL_QUADS);
3427 glTexCoord2f(0.0, 0.0);
3428 glVertex3d(rdst.left + x,
3429 rdst.top + y,
3430 0.5);
3431 glTexCoord2f(1.0, 0.0);
3432 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3433 rdst.top + y,
3434 0.5);
3435 glTexCoord2f(1.0, 1.0);
3436 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3437 rdst.top + (y + UNLOCK_TEX_SIZE),
3438 0.5);
3439 glTexCoord2f(0.0, 1.0);
3440 glVertex3d(rdst.left + x,
3441 rdst.top + (y + UNLOCK_TEX_SIZE),
3442 0.5);
3443 glEnd();
3447 upload_surface_to_tex_memory_release();
3448 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3450 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3451 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3452 glDrawBuffer(prev_draw);
3454 LEAVE_GL();
3456 return DD_OK;
3459 void
3460 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3462 GLfloat height, width;
3463 GLfloat trans_mat[16];
3465 TRACE("(%p)\n", This);
3467 width = This->surface->surface_desc.dwWidth;
3468 height = This->surface->surface_desc.dwHeight;
3470 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3471 * to OpenGL screen coordinates (ie the upper left corner is not the same).
3473 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3474 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3475 #if 0
3476 /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3477 * that the Z coordinate needs to be given to GL unchanged.
3479 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 2.0; trans_mat[14] = -1.0;
3480 #endif
3481 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = 0.0;
3482 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3484 ENTER_GL();
3485 glMatrixMode(GL_MODELVIEW);
3486 glLoadIdentity();
3487 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3488 Correctness Tips section).
3490 Basically, from what I understood, if the game does not filter the font texture,
3491 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3492 one and we will have strange artifacts (as the rounding and stuff may give different results
3493 for different pixels, ie sometimes take the left pixel, sometimes the right).
3495 glTranslatef(0.375, 0.375, 0);
3496 glMatrixMode(GL_PROJECTION);
3497 glLoadMatrixf(trans_mat);
3498 LEAVE_GL();
3501 void
3502 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3503 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3505 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3507 ENTER_GL();
3508 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3509 glMatrixMode(GL_MODELVIEW);
3510 glLoadMatrixf((float *) view_mat);
3512 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3513 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3514 GLint i;
3515 DWORD runner;
3516 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3517 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3518 GLdouble plane[4];
3520 plane[0] = This->clipping_planes[i].plane[0];
3521 plane[1] = This->clipping_planes[i].plane[1];
3522 plane[2] = This->clipping_planes[i].plane[2];
3523 plane[3] = This->clipping_planes[i].plane[3];
3525 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3529 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3530 GLint i;
3532 for (i = 0; i < This->max_active_lights; i++ )
3534 DWORD dwLightIndex = This->active_lights[i];
3535 if (dwLightIndex != ~0)
3537 LPD3DLIGHT7 pLight = &This->light_parameters[dwLightIndex];
3538 switch (pLight->dltType)
3540 case D3DLIGHT_DIRECTIONAL: {
3541 float direction[4];
3542 float cut_off = 180.0;
3544 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3545 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3546 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3547 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3549 direction[0] = pLight->dvDirection.u1.x;
3550 direction[1] = pLight->dvDirection.u2.y;
3551 direction[2] = pLight->dvDirection.u3.z;
3552 direction[3] = 0.0;
3553 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3554 } break;
3556 case D3DLIGHT_POINT: {
3557 float position[4];
3558 float cut_off = 180.0;
3560 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3561 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3562 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3563 position[0] = pLight->dvPosition.u1.x;
3564 position[1] = pLight->dvPosition.u2.y;
3565 position[2] = pLight->dvPosition.u3.z;
3566 position[3] = 1.0;
3567 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3568 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3569 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3570 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3571 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3572 } break;
3574 case D3DLIGHT_SPOT: {
3575 float direction[4];
3576 float position[4];
3577 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3579 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &pLight->dcvAmbient);
3580 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &pLight->dcvDiffuse);
3581 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3583 direction[0] = pLight->dvDirection.u1.x;
3584 direction[1] = pLight->dvDirection.u2.y;
3585 direction[2] = pLight->dvDirection.u3.z;
3586 direction[3] = 0.0;
3587 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3588 position[0] = pLight->dvPosition.u1.x;
3589 position[1] = pLight->dvPosition.u2.y;
3590 position[2] = pLight->dvPosition.u3.z;
3591 position[3] = 1.0;
3592 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3593 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3594 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3595 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3596 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3597 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &pLight->dvFalloff);
3598 } break;
3600 default:
3601 /* No warning here as it's already done at light setting */
3602 break;
3608 glMultMatrixf((float *) world_mat);
3610 if ((matrices & PROJMAT_CHANGED) != 0) {
3611 glMatrixMode(GL_PROJECTION);
3612 glLoadMatrixf((float *) proj_mat);
3614 LEAVE_GL();
3617 void
3618 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3620 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3621 DWORD tex_mat, tex_stage;
3623 TRACE("(%p,%08lx)\n", This, matrices);
3625 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3626 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3627 /* This will force an update of the transform state at the next drawing. */
3628 glThis->transform_state = GL_TRANSFORM_NONE;
3631 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3632 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3634 ENTER_GL();
3635 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3636 GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3637 if (matrices & tex_mat) {
3638 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3639 int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3641 if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3642 if (glThis->current_active_tex_unit != unit) {
3643 GL_extensions.glActiveTexture(unit);
3644 glThis->current_active_tex_unit = unit;
3646 glMatrixMode(GL_TEXTURE);
3647 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3649 This->tex_mat_is_identity[tex_stage] = is_identity;
3650 } else {
3651 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3652 if (glThis->current_active_tex_unit != unit) {
3653 GL_extensions.glActiveTexture(unit);
3654 glThis->current_active_tex_unit = unit;
3656 glMatrixMode(GL_TEXTURE);
3657 glLoadIdentity();
3658 This->tex_mat_is_identity[tex_stage] = TRUE;
3663 LEAVE_GL();
3667 /* TODO for both these functions :
3668 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3669 by other OpenGL code in D3D
3670 - handle the case where no 'Begin / EndScene' was done between two locks
3671 - handle the rectangles in the unlock too
3672 - handle pitch correctly...
3674 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3676 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3677 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3678 WINE_GL_BUFFER_TYPE buffer_type;
3679 RECT loc_rect;
3681 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3682 buffer_type = WINE_GL_BUFFER_FRONT;
3683 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3684 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3685 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3687 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3688 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3689 buffer_type = WINE_GL_BUFFER_BACK;
3690 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3691 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3692 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3694 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3695 } else {
3696 ERR("Wrong surface type for locking !\n");
3697 return;
3700 if (pRect == NULL) {
3701 loc_rect.top = 0;
3702 loc_rect.left = 0;
3703 loc_rect.bottom = This->surface_desc.dwHeight;
3704 loc_rect.right = This->surface_desc.dwWidth;
3705 pRect = &loc_rect;
3708 /* Try to acquire the device critical section */
3709 EnterCriticalSection(&(d3d_dev->crit));
3711 if (gl_d3d_dev->lock_rect_valid[buffer_type]) {
3712 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3713 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3715 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3717 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3718 /* Check if the new rectangle is in the previous one or not.
3719 If it is not, flush first the previous locks on screen.
3721 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3722 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3723 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3724 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3725 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3726 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3727 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3728 pRect->left, pRect->top, pRect->right, pRect->bottom,
3729 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3730 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3731 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3733 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3734 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3736 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3737 } else {
3738 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3741 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3742 /* If the surface is already in memory, no need to do anything here... */
3743 GLenum buffer_format;
3744 GLenum buffer_color;
3745 int y;
3746 char *dst;
3748 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3749 pRect->left, pRect->top, pRect->right, pRect->bottom);
3751 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3752 may only write to the device... But when we will blit it back to the screen, we need
3753 also to blit correctly the parts the application did not overwrite... */
3755 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3756 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3757 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3758 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3759 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3760 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3761 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3762 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3763 buffer_color = GL_RGB;
3764 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3765 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3766 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3767 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3768 buffer_format = GL_UNSIGNED_BYTE;
3769 buffer_color = GL_RGB;
3770 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3771 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3772 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3773 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3774 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3775 buffer_color = GL_BGRA;
3776 } else {
3777 ERR(" unsupported pixel format at device locking.\n");
3778 return;
3780 } else {
3781 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3782 return;
3785 ENTER_GL();
3787 if (buffer_type == WINE_GL_BUFFER_FRONT)
3788 /* Application wants to lock the front buffer */
3789 glReadBuffer(GL_FRONT);
3790 else
3791 /* Application wants to lock the back buffer */
3792 glReadBuffer(GL_BACK);
3794 dst = ((char *)This->surface_desc.lpSurface) +
3795 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3797 if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3798 /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3799 * could not be bothered considering the rare cases where it may be useful :-)
3801 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3802 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3803 y--) {
3804 glReadPixels(pRect->left, y,
3805 pRect->right - pRect->left, 1,
3806 buffer_color, buffer_format, dst);
3807 dst += This->surface_desc.u1.lPitch;
3809 } else {
3810 /* Faster path for surface copy. Note that I can use static variables here as I am
3811 * protected by the OpenGL critical section so this function won't be called by
3812 * two threads at the same time.
3814 static char *buffer = NULL;
3815 static int buffer_width = 0;
3816 char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3817 int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3819 glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3820 pRect->right - pRect->left, pRect->bottom - pRect->top,
3821 buffer_color, buffer_format, dst);
3823 if (current_width > buffer_width) {
3824 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3825 buffer_width = current_width;
3826 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3828 for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3829 memcpy(buffer, dst, current_width);
3830 memcpy(dst, dst2, current_width);
3831 memcpy(dst2, buffer, current_width);
3832 dst += This->surface_desc.u1.lPitch;
3833 dst2 -= This->surface_desc.u1.lPitch;
3837 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3839 #if 0
3840 /* I keep this code here as it's very useful to debug :-) */
3842 static int flush_count = 0;
3843 char buf[128];
3844 FILE *f;
3846 if ((++flush_count % 50) == 0) {
3847 sprintf(buf, "lock_%06d.pnm", flush_count);
3848 f = fopen(buf, "wb");
3849 DDRAW_dump_surface_to_disk(This, f);
3852 #endif
3854 LEAVE_GL();
3858 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3859 RECT loc_rect;
3860 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3861 int x, y;
3862 BOOLEAN initial;
3863 DWORD opt_bitmap;
3865 /* Note : no need here to lock the 'device critical section' as we are already protected by
3866 the GL critical section. */
3868 if (pRect == NULL) {
3869 loc_rect.top = 0;
3870 loc_rect.left = 0;
3871 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3872 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3873 pRect = &loc_rect;
3876 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3878 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3880 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3881 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3882 ERR(" unsupported pixel format at frame buffer flush.\n");
3883 return;
3886 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3887 RECT flush_rect;
3889 flush_rect.top = y;
3890 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3892 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3893 /* First, upload the texture... */
3894 flush_rect.left = x;
3895 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3897 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3899 glBegin(GL_QUADS);
3900 glTexCoord2f(0.0, 0.0);
3901 glVertex3d(x, y, 0.5);
3902 glTexCoord2f(1.0, 0.0);
3903 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3904 glTexCoord2f(1.0, 1.0);
3905 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3906 glTexCoord2f(0.0, 1.0);
3907 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3908 glEnd();
3912 upload_surface_to_tex_memory_release();
3913 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3915 #if 0
3916 /* I keep this code here as it's very useful to debug :-) */
3918 static int flush_count = 0;
3919 char buf[128];
3920 FILE *f;
3922 if ((++flush_count % 50) == 0) {
3923 sprintf(buf, "flush_%06d.pnm", flush_count);
3924 f = fopen(buf, "wb");
3925 DDRAW_dump_surface_to_disk(surf, f);
3928 #endif
3931 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3933 WINE_GL_BUFFER_TYPE buffer_type;
3934 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3935 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3937 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3938 buffer_type = WINE_GL_BUFFER_FRONT;
3939 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3940 buffer_type = WINE_GL_BUFFER_BACK;
3941 } else {
3942 ERR("Wrong surface type for locking !\n");
3943 return;
3946 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3947 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3948 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3950 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3952 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3953 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3954 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3955 GLint prev_draw;
3957 TRACE(" flushing front buffer immediately on screen.\n");
3959 ENTER_GL();
3960 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3961 glDrawBuffer(GL_FRONT);
3962 /* Note: we do not use the application provided lock rectangle but our own stored at
3963 lock time. This is because in old D3D versions, the 'lock' parameter did not
3964 exist.
3966 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]);
3967 glDrawBuffer(prev_draw);
3968 LEAVE_GL();
3969 } else {
3970 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3974 /* And 'frees' the device critical section */
3975 LeaveCriticalSection(&(d3d_dev->crit));
3978 static void
3979 apply_texture_state(IDirect3DDeviceImpl *This)
3981 int stage, state;
3983 /* Initialize texture stages states */
3984 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3985 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3986 if (This->state_block.set_flags.texture_stage_state[stage][state]) {
3987 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3988 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3994 HRESULT
3995 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, int version)
3997 IDirect3DDeviceImpl *object;
3998 IDirect3DDeviceGLImpl *gl_object;
3999 IDirectDrawSurfaceImpl *surf;
4000 HDC device_context;
4001 XVisualInfo *vis;
4002 int num;
4003 int tex_num;
4004 XVisualInfo template;
4005 GLenum buffer = GL_FRONT;
4006 int light;
4008 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
4009 if (object == NULL) return DDERR_OUTOFMEMORY;
4011 gl_object = (IDirect3DDeviceGLImpl *) object;
4013 object->ref = 1;
4014 object->d3d = d3d;
4015 object->surface = surface;
4016 object->set_context = set_context;
4017 object->clear = d3ddevice_clear_back;
4018 object->set_matrices = d3ddevice_set_matrices;
4019 object->matrices_updated = d3ddevice_matrices_updated;
4020 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
4021 object->version = version;
4023 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
4025 InitializeCriticalSection(&(object->crit));
4027 TRACE(" device critical section : %p\n", &(object->crit));
4029 device_context = GetDC(surface->ddraw_owner->window);
4030 gl_object->display = get_display(device_context);
4031 gl_object->drawable = get_drawable(device_context);
4032 ReleaseDC(surface->ddraw_owner->window,device_context);
4034 ENTER_GL();
4035 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
4036 vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
4037 if (vis == NULL) {
4038 HeapFree(GetProcessHeap(), 0, object);
4039 ERR("No visual found !\n");
4040 LEAVE_GL();
4041 return DDERR_INVALIDPARAMS;
4042 } else {
4043 TRACE(" visual found\n");
4046 gl_object->gl_context = glXCreateContext(gl_object->display, vis,
4047 NULL, GL_TRUE);
4049 if (gl_object->gl_context == NULL) {
4050 HeapFree(GetProcessHeap(), 0, object);
4051 ERR("Error in context creation !\n");
4052 LEAVE_GL();
4053 return DDERR_INVALIDPARAMS;
4054 } else {
4055 TRACE(" context created (%p)\n", gl_object->gl_context);
4058 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
4059 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4060 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
4061 surf->aux_ctx = (LPVOID) object;
4062 surf->aux_data = (LPVOID) gl_object->drawable;
4063 surf->aux_flip = opengl_flip;
4064 buffer = GL_BACK;
4065 break;
4068 /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
4069 if (surf == NULL) {
4070 TRACE(" no double buffering : drawing on the front buffer\n");
4071 buffer = GL_FRONT;
4074 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4075 IDirectDrawSurfaceImpl *surf2;
4076 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
4077 for (; surf2 != NULL; surf2 = surf2->next_attached) {
4078 TRACE(" checking surface %p :", surf2);
4079 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
4080 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
4081 /* Override the Lock / Unlock function for all these surfaces */
4082 surf2->lock_update_prev = surf2->lock_update;
4083 surf2->lock_update = d3ddevice_lock_update;
4084 surf2->unlock_update_prev = surf2->unlock_update;
4085 surf2->unlock_update = d3ddevice_unlock_update;
4086 /* And install also the blt / bltfast overrides */
4087 surf2->aux_blt = d3ddevice_blt;
4088 surf2->aux_bltfast = d3ddevice_bltfast;
4090 TRACE(" overriding direct surface access.\n");
4091 } else {
4092 TRACE(" no override.\n");
4094 surf2->d3ddevice = object;
4098 /* Set the various light parameters */
4099 object->num_set_lights = 0;
4100 object->max_active_lights = opengl_device_caps.dwMaxActiveLights;
4101 object->light_parameters = NULL;
4102 object->active_lights = HeapAlloc(GetProcessHeap(), 0,
4103 object->max_active_lights * sizeof(object->active_lights[0]));
4104 /* Fill the active light array with ~0, which is used to indicate an
4105 invalid light index. We don't use 0, because it's a valid light index. */
4106 for (light=0; light < object->max_active_lights; light++)
4107 object->active_lights[light] = ~0;
4110 /* Allocate memory for the matrices */
4111 object->world_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4112 object->view_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4113 object->proj_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4114 memcpy(object->world_mat, id_mat, 16 * sizeof(float));
4115 memcpy(object->view_mat , id_mat, 16 * sizeof(float));
4116 memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
4117 for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
4118 object->tex_mat[tex_num] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4119 memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
4120 object->tex_mat_is_identity[tex_num] = TRUE;
4123 /* Initialisation */
4124 TRACE(" setting current context\n");
4125 object->set_context(object);
4126 TRACE(" current context set\n");
4128 /* allocate the clipping planes */
4129 object->max_clipping_planes = opengl_device_caps.wMaxUserClipPlanes;
4130 object->clipping_planes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
4132 glHint(GL_FOG_HINT,GL_NICEST);
4134 /* Initialize the various GL contexts to be in sync with what we store locally */
4135 glClearDepth(0.0);
4136 glClearStencil(0);
4137 glClearColor(0.0, 0.0, 0.0, 0.0);
4138 glDepthMask(GL_TRUE);
4139 gl_object->depth_mask = TRUE;
4140 glEnable(GL_DEPTH_TEST);
4141 gl_object->depth_test = TRUE;
4142 glDisable(GL_ALPHA_TEST);
4143 glDisable(GL_STENCIL_TEST);
4144 glDisable(GL_CULL_FACE);
4145 glDisable(GL_LIGHTING);
4146 glDisable(GL_BLEND);
4147 glDisable(GL_FOG);
4148 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4149 gl_object->current_tex_env = GL_REPLACE;
4150 gl_object->current_active_tex_unit = GL_TEXTURE0_WINE;
4151 if (GL_extensions.glActiveTexture != NULL) {
4152 GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
4154 gl_object->current_alpha_test_ref = 0.0;
4155 gl_object->current_alpha_test_func = GL_ALWAYS;
4156 glAlphaFunc(GL_ALWAYS, 0.0);
4158 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4159 glDrawBuffer(buffer);
4160 glReadBuffer(buffer);
4161 /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
4162 LEAVE_GL();
4164 gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
4165 gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
4167 /* fill_device_capabilities(d3d->ddraw); */
4169 ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
4170 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
4171 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
4172 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
4174 *obj = object;
4176 TRACE(" creating implementation at %p.\n", *obj);
4178 /* And finally warn D3D that this device is now present */
4179 object->d3d->d3d_added_device(object->d3d, object);
4181 InitDefaultStateBlock(&object->state_block, object->version);
4182 /* Apply default render state and texture stage state values */
4183 apply_render_state(object, &object->state_block);
4184 apply_texture_state(object);
4186 /* And fill the fog table with the default fog value */
4187 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4189 return DD_OK;
4192 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4194 pc->dwSize = sizeof(*pc);
4195 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4196 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4197 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4198 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4199 D3DPRASTERCAPS_ZFOG;
4200 if (GL_extensions.mipmap_lodbias) {
4201 pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4203 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4204 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4205 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4206 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4207 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4208 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4209 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4210 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4211 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4212 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4213 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4214 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4215 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4216 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4217 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4218 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4219 D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4220 D3DPTFILTERCAPS_MIPFPOINT;
4221 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4222 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4223 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4224 if (GL_extensions.mirrored_repeat) {
4225 pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4227 pc->dwStippleWidth = 32;
4228 pc->dwStippleHeight = 32;
4231 static void fill_caps(void)
4233 GLint max_clip_planes;
4234 GLint depth_bits;
4236 /* Fill first all the fields with default values which will be overriden later on with
4237 correct ones from the GL code
4239 opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4240 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4241 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4242 /* D3D 7 capabilities */
4243 D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4244 fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4245 fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4246 opengl_device_caps.dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
4247 opengl_device_caps.dwMinTextureWidth = 1;
4248 opengl_device_caps.dwMinTextureHeight = 1;
4249 opengl_device_caps.dwMaxTextureWidth = 1024;
4250 opengl_device_caps.dwMaxTextureHeight = 1024;
4251 opengl_device_caps.dwMaxTextureRepeat = 16;
4252 opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4253 opengl_device_caps.dwMaxAnisotropy = 0;
4254 opengl_device_caps.dvGuardBandLeft = 0.0;
4255 opengl_device_caps.dvGuardBandRight = 0.0;
4256 opengl_device_caps.dvGuardBandTop = 0.0;
4257 opengl_device_caps.dvGuardBandBottom = 0.0;
4258 opengl_device_caps.dvExtentsAdjust = 0.0;
4259 opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4260 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4261 opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4262 D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4263 D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4264 if (GL_extensions.max_texture_units != 0) {
4265 opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4266 opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4267 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4268 } else {
4269 opengl_device_caps.wMaxTextureBlendStages = 1;
4270 opengl_device_caps.wMaxSimultaneousTextures = 1;
4271 opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4273 opengl_device_caps.dwMaxActiveLights = 16;
4274 opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4275 opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4276 opengl_device_caps.wMaxUserClipPlanes = 1;
4277 opengl_device_caps.wMaxVertexBlendMatrices = 0;
4278 opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4279 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4280 opengl_device_caps.dwReserved1 = 0;
4281 opengl_device_caps.dwReserved2 = 0;
4282 opengl_device_caps.dwReserved3 = 0;
4283 opengl_device_caps.dwReserved4 = 0;
4285 /* And now some GL overrides :-) */
4286 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4287 opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4288 opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4289 TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4291 glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4292 TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4294 glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4295 opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4296 TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4298 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4299 TRACE(": Z bits = %d\n", depth_bits);
4300 switch (depth_bits) {
4301 case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4302 case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4303 case 32:
4304 default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4308 BOOL
4309 d3ddevice_init_at_startup(void *gl_handle)
4311 XVisualInfo template;
4312 XVisualInfo *vis;
4313 HDC device_context;
4314 Display *display;
4315 Visual *visual;
4316 Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4317 XWindowAttributes win_attr;
4318 GLXContext gl_context;
4319 int num;
4320 const char *glExtensions;
4321 const char *glVersion;
4322 const char *glXExtensions = NULL;
4323 const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4324 int major, minor, patch, num_parsed;
4326 TRACE("Initializing GL...\n");
4328 if (!drawable)
4330 WARN("x11drv not loaded - D3D support disabled!\n");
4331 return FALSE;
4334 /* Get a default rendering context to have the 'caps' function query some info from GL */
4335 device_context = GetDC(0);
4336 display = get_display(device_context);
4337 ReleaseDC(0, device_context);
4339 ENTER_GL();
4340 if (XGetWindowAttributes(display, drawable, &win_attr)) {
4341 visual = win_attr.visual;
4342 } else {
4343 visual = DefaultVisual(display, DefaultScreen(display));
4345 template.visualid = XVisualIDFromVisual(visual);
4346 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4347 if (vis == NULL) {
4348 LEAVE_GL();
4349 WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4350 return FALSE;
4352 gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4353 XFree(vis);
4355 if (gl_context == NULL) {
4356 LEAVE_GL();
4357 WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4358 return FALSE;
4360 if (glXMakeCurrent(display, drawable, gl_context) == False) {
4361 glXDestroyContext(display, gl_context);
4362 LEAVE_GL();
4363 WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4364 return FALSE;
4367 /* Then, query all extensions */
4368 glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4369 glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4370 glVersion = (const char *) glGetString(GL_VERSION);
4371 if (gl_handle != NULL) {
4372 pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4375 /* Parse the GL version string */
4376 num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4377 if (num_parsed == 1) {
4378 minor = 0;
4379 patch = 0;
4380 } else if (num_parsed == 2) {
4381 patch = 0;
4383 TRACE("GL version %d.%d.%d\n", major, minor, patch);
4385 /* And starts to fill the extension context properly */
4386 memset(&GL_extensions, 0, sizeof(GL_extensions));
4387 TRACE("GL supports following extensions used by Wine :\n");
4389 /* Mirrored Repeat extension :
4390 - GL_ARB_texture_mirrored_repeat
4391 - GL_IBM_texture_mirrored_repeat
4392 - GL >= 1.4
4394 if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4395 (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4396 (major > 1) ||
4397 ((major == 1) && (minor >= 4))) {
4398 TRACE(" - mirrored repeat\n");
4399 GL_extensions.mirrored_repeat = TRUE;
4402 /* Texture LOD Bias :
4403 - GL_EXT_texture_lod_bias
4405 if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4406 TRACE(" - texture lod bias\n");
4407 GL_extensions.mipmap_lodbias = TRUE;
4410 /* For all subsequent extensions, we need glXGetProcAddress */
4411 if (pglXGetProcAddressARB != NULL) {
4412 /* Multi-texturing :
4413 - GL_ARB_multitexture
4414 - GL >= 1.2.1
4416 if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4417 (major > 1) ||
4418 ((major == 1) && (minor > 2)) ||
4419 ((major == 1) && (minor == 2) && (patch >= 1))) {
4420 glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4421 TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4422 /* We query the ARB version to be the most portable we can... */
4423 GL_extensions.glActiveTexture = pglXGetProcAddressARB( (const GLubyte *) "glActiveTextureARB");
4424 GL_extensions.glMultiTexCoord[0] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord1fvARB");
4425 GL_extensions.glMultiTexCoord[1] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord2fvARB");
4426 GL_extensions.glMultiTexCoord[2] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord3fvARB");
4427 GL_extensions.glMultiTexCoord[3] = pglXGetProcAddressARB( (const GLubyte *) "glMultiTexCoord4fvARB");
4428 GL_extensions.glClientActiveTexture = pglXGetProcAddressARB( (const GLubyte *) "glClientActiveTextureARB");
4429 } else {
4430 GL_extensions.max_texture_units = 0;
4433 if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4434 TRACE(" - S3TC compression supported\n");
4435 GL_extensions.s3tc_compressed_texture = TRUE;
4436 GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB( (const GLubyte *) "glCompressedTexImage2DARB");
4437 GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB( (const GLubyte *) "glCompressedTexSubImage2DARB");
4441 /* Fill the D3D capabilities according to what GL tells us... */
4442 fill_caps();
4444 /* And frees this now-useless context */
4445 glXMakeCurrent(display, None, NULL);
4446 glXDestroyContext(display, gl_context);
4447 LEAVE_GL();
4449 return TRUE;