- some TRACEing fixes
[wine/wine64.git] / dlls / ddraw / d3ddevice / mesa.c
blob72781dcb16d98d40249c5e081070c635b5d60554
1 /* Direct3D Device
2 * Copyright (c) 1998 Lionel ULMER
4 * This file contains the MESA implementation of all the D3D devices that
5 * Wine supports.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <string.h>
25 #include <math.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 #include "ddraw.h"
33 #include "d3d.h"
34 #include "wine/debug.h"
36 #include "mesa_private.h"
37 #include "main.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
40 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
42 #undef COMPUTE_FPS
44 /* x11drv GDI escapes */
45 #define X11DRV_ESCAPE 6789
46 enum x11drv_escape_codes
48 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
49 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
50 X11DRV_GET_FONT, /* get current X font for a DC */
53 /* They are non-static as they are used by Direct3D in the creation function */
54 const GUID IID_D3DDEVICE_OpenGL = {
55 0x31416d44,
56 0x86ae,
57 0x11d2,
58 { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
61 const float id_mat[16] = {
62 1.0, 0.0, 0.0, 0.0,
63 0.0, 1.0, 0.0, 0.0,
64 0.0, 0.0, 1.0, 0.0,
65 0.0, 0.0, 0.0, 1.0
68 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
69 D3DPRIMITIVETYPE d3dptPrimitiveType,
70 DWORD d3dvtVertexType,
71 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
72 DWORD dwVertexCount,
73 LPWORD dwIndices,
74 DWORD dwIndexCount,
75 DWORD dwFlags) ;
77 static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
79 /* retrieve the X display to use on a given DC */
80 inline static Display *get_display( HDC hdc )
82 Display *display;
83 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
85 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
86 sizeof(display), (LPSTR)&display )) display = NULL;
88 return display;
91 #define UNLOCK_TEX_SIZE 256
93 #define DEPTH_RANGE_BIT (0x00000001 << 0)
94 #define VIEWPORT_BIT (0x00000001 << 1)
96 static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
97 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
98 DWORD opt_bitmap = 0x00000000;
100 if (gl_d3d_dev->unlock_tex == 0) {
101 glGenTextures(1, &gl_d3d_dev->unlock_tex);
102 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
103 *initial = TRUE;
104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
107 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
108 } else {
109 glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
111 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
112 glMatrixMode(GL_TEXTURE);
113 glLoadIdentity();
116 if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
117 gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
118 d3ddevice_set_ortho(d3d_dev);
121 if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
122 if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
123 (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
124 glEnable(GL_TEXTURE_2D);
125 glEnable(GL_SCISSOR_TEST);
126 if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
127 (d3d_dev->active_viewport.dvMaxZ != 1.0)) {
128 glDepthRange(0.0, 1.0);
129 opt_bitmap |= DEPTH_RANGE_BIT;
131 if ((d3d_dev->active_viewport.dwX != 0) ||
132 (d3d_dev->active_viewport.dwY != 0) ||
133 (d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
134 (d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
135 glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
136 opt_bitmap |= VIEWPORT_BIT;
138 glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
139 pRect->right - pRect->left, pRect->bottom - pRect->top);
140 if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
141 if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
142 if (use_alpha) {
143 if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
144 if (((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) != 0x00) ||
145 ((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]) != D3DCMP_GREATER)) {
146 glAlphaFunc(GL_GREATER, 0.0);
148 } else {
149 if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
151 if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
152 if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
153 if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
154 if (gl_d3d_dev->current_tex_env != GL_REPLACE)
155 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
157 return opt_bitmap;
160 static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
161 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
163 /* And restore all the various states modified by this code */
164 if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
165 if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
166 if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
167 glEnable(GL_ALPHA_TEST);
168 else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
169 glDisable(GL_ALPHA_TEST);
170 if (use_alpha) {
171 if (((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) != 0x00) ||
172 ((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]) != D3DCMP_GREATER)) {
173 glAlphaFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]),
174 (d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) / 255.0);
177 if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
178 if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
179 if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
180 if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
181 glDisable(GL_SCISSOR_TEST);
182 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
183 if (opt_bitmap & DEPTH_RANGE_BIT) {
184 glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
186 if (opt_bitmap & VIEWPORT_BIT) {
187 glViewport(d3d_dev->active_viewport.dwX,
188 d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
189 d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
191 if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
192 d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
195 /* This is a hack to prevent querying the current texture from GL. Basically, at the next
196 DrawPrimitive call, this will bind the correct texture to this stage. */
197 gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
198 if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
201 /* retrieve the X drawable to use on a given DC */
202 inline static Drawable get_drawable( HDC hdc )
204 Drawable drawable;
205 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
207 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
208 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
210 return drawable;
213 #ifdef COMPUTE_FPS
215 #define MEASUREMENT_WINDOW 20
216 #define NUMBER_OF_WINDOWS 4
218 static LONGLONG perf_freq;
219 static LONGLONG perf_storage[NUMBER_OF_WINDOWS];
220 static LONGLONG prev_time = 0;
221 static unsigned int current_window;
222 static unsigned int measurements_in_window;
223 static unsigned int valid_windows;
225 #endif
227 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
229 IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
230 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
232 TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
233 ENTER_GL();
234 if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
235 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]);
237 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
238 gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
239 glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
240 LEAVE_GL();
242 #ifdef COMPUTE_FPS
244 LONGLONG current_time;
245 LONGLONG frame_duration;
246 QueryPerformanceCounter((LARGE_INTEGER *) &current_time);
248 if (prev_time != 0) {
249 LONGLONG total_time = 0;
250 int tot_meas;
252 frame_duration = current_time - prev_time;
253 prev_time = current_time;
255 perf_storage[current_window] += frame_duration;
256 measurements_in_window++;
258 if (measurements_in_window >= MEASUREMENT_WINDOW) {
259 current_window++;
260 valid_windows++;
262 if (valid_windows < NUMBER_OF_WINDOWS) {
263 int i;
264 tot_meas = valid_windows * MEASUREMENT_WINDOW;
265 for (i = 0; i < valid_windows; i++) {
266 total_time += perf_storage[i];
268 } else {
269 int i;
270 tot_meas = NUMBER_OF_WINDOWS * MEASUREMENT_WINDOW;
271 for (i = 0; i < NUMBER_OF_WINDOWS; i++) {
272 total_time += perf_storage[i];
276 DPRINTF("FPS : %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time);
278 if (current_window >= NUMBER_OF_WINDOWS) {
279 current_window = 0;
281 perf_storage[current_window] = 0;
283 } else {
284 prev_time = current_time;
285 memset(perf_storage, 0, sizeof(perf_storage));
286 current_window = 0;
287 valid_windows = 0;
288 measurements_in_window = 0;
289 QueryPerformanceFrequency((LARGE_INTEGER *) &perf_freq);
292 #endif
294 return TRUE;
298 /*******************************************************************************
299 * OpenGL static functions
301 static void set_context(IDirect3DDeviceImpl* This)
303 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
305 TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
306 ENTER_GL();
307 if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
308 ERR("Error in setting current context (context %p drawable %ld)!\n",
309 glThis->gl_context, glThis->drawable);
311 LEAVE_GL();
314 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
316 pc->dwSize = sizeof(*pc);
317 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
318 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
319 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
320 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL;
321 pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
322 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
323 pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
324 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
325 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
326 pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
327 D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
328 D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
329 pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
330 D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
331 pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
332 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
333 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
334 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
335 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
336 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
337 pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
338 D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
339 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
340 pc->dwStippleWidth = 32;
341 pc->dwStippleHeight = 32;
344 static void fill_opengl_caps(D3DDEVICEDESC *d1)
346 /* GLint maxlight; */
348 d1->dwSize = sizeof(*d1);
349 d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
350 | D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
351 d1->dcmColorModel = D3DCOLOR_RGB;
352 d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
353 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
354 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
355 /* D3D 7 capabilities */
356 D3DDEVCAPS_DRAWPRIMITIVES2 | D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_HWRASTERIZATION;
357 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
358 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
359 d1->bClipping = TRUE;
360 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
361 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
362 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
363 d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
364 fill_opengl_primcaps(&(d1->dpcLineCaps));
365 fill_opengl_primcaps(&(d1->dpcTriCaps));
366 d1->dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
367 d1->dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32;
368 d1->dwMaxBufferSize = 0;
369 d1->dwMaxVertexCount = 65536;
370 d1->dwMinTextureWidth = 1;
371 d1->dwMinTextureHeight = 1;
372 d1->dwMaxTextureWidth = 1024;
373 d1->dwMaxTextureHeight = 1024;
374 d1->dwMinStippleWidth = 1;
375 d1->dwMinStippleHeight = 1;
376 d1->dwMaxStippleWidth = 32;
377 d1->dwMaxStippleHeight = 32;
378 d1->dwMaxTextureRepeat = 16;
379 d1->dwMaxTextureAspectRatio = 1024;
380 d1->dwMaxAnisotropy = 0;
381 d1->dvGuardBandLeft = 0.0;
382 d1->dvGuardBandRight = 0.0;
383 d1->dvGuardBandTop = 0.0;
384 d1->dvGuardBandBottom = 0.0;
385 d1->dvExtentsAdjust = 0.0;
386 d1->dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
387 D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
388 d1->dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
389 d1->dwTextureOpCaps = 0; /* TODO add proper caps according to OpenGL multi-texture stuff */
390 d1->wMaxTextureBlendStages = 1; /* TODO add proper caps according to OpenGL multi-texture stuff */
391 d1->wMaxSimultaneousTextures = 1; /* TODO add proper caps according to OpenGL multi-texture stuff */
394 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
396 D3DDEVICEDESC d1;
398 /* Copy first D3D1/2/3 capabilities */
399 fill_opengl_caps(&d1);
401 /* And fill the D3D7 one with it */
402 d->dwDevCaps = d1.dwDevCaps;
403 d->dpcLineCaps = d1.dpcLineCaps;
404 d->dpcTriCaps = d1.dpcTriCaps;
405 d->dwDeviceRenderBitDepth = d1.dwDeviceRenderBitDepth;
406 d->dwDeviceZBufferBitDepth = d1.dwDeviceZBufferBitDepth;
407 d->dwMinTextureWidth = d1.dwMinTextureWidth;
408 d->dwMinTextureHeight = d1.dwMinTextureHeight;
409 d->dwMaxTextureWidth = d1.dwMaxTextureWidth;
410 d->dwMaxTextureHeight = d1.dwMaxTextureHeight;
411 d->dwMaxTextureRepeat = d1.dwMaxTextureRepeat;
412 d->dwMaxTextureAspectRatio = d1.dwMaxTextureAspectRatio;
413 d->dwMaxAnisotropy = d1.dwMaxAnisotropy;
414 d->dvGuardBandLeft = d1.dvGuardBandLeft;
415 d->dvGuardBandTop = d1.dvGuardBandTop;
416 d->dvGuardBandRight = d1.dvGuardBandRight;
417 d->dvGuardBandBottom = d1.dvGuardBandBottom;
418 d->dvExtentsAdjust = d1.dvExtentsAdjust;
419 d->dwStencilCaps = d1.dwStencilCaps;
420 d->dwFVFCaps = d1.dwFVFCaps;
421 d->dwTextureOpCaps = d1.dwTextureOpCaps;
422 d->wMaxTextureBlendStages = d1.wMaxTextureBlendStages;
423 d->wMaxSimultaneousTextures = d1.wMaxSimultaneousTextures;
424 d->dwMaxActiveLights = d1.dlcLightingCaps.dwNumLights;
425 d->dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
426 d->deviceGUID = IID_IDirect3DTnLHalDevice;
427 d->wMaxUserClipPlanes = 1;
428 d->wMaxVertexBlendMatrices = 0;
429 d->dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG | D3DVTXPCAPS_DIRECTIONALLIGHTS |
430 D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
431 d->dwReserved1 = 0;
432 d->dwReserved2 = 0;
433 d->dwReserved3 = 0;
434 d->dwReserved4 = 0;
437 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
439 D3DDEVICEDESC dref, d1, d2;
440 HRESULT ret_value;
442 /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
443 Let's put the string in a sufficiently sized array in writable memory. */
444 char device_name[50];
445 strcpy(device_name,"direct3d");
447 fill_opengl_caps(&dref);
449 if (version > 1) {
450 /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
451 TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
452 d1 = dref;
453 d2 = dref;
454 ret_value = cb((LPIID) &IID_IDirect3DRefDevice, "WINE Reference Direct3DX using OpenGL", device_name, &d1, &d2, context);
455 if (ret_value != D3DENUMRET_OK)
456 return ret_value;
459 TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
460 d1 = dref;
461 d2 = dref;
462 ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, "WINE Direct3DX using OpenGL", device_name, &d1, &d2, context);
463 if (ret_value != D3DENUMRET_OK)
464 return ret_value;
466 return D3DENUMRET_OK;
469 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
471 D3DDEVICEDESC7 ddesc;
473 fill_opengl_caps_7(&ddesc);
475 TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
477 return cb("WINE Direct3D7 using OpenGL", "Wine D3D7 device", &ddesc, context);
480 ULONG WINAPI
481 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
483 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
484 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
486 TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, This->ref);
487 if (!--(This->ref)) {
488 int i;
489 IDirectDrawSurfaceImpl *surface = This->surface, *surf;
491 /* Release texture associated with the device */
492 for (i = 0; i < MAX_TEXTURES; i++) {
493 if (This->current_texture[i] != NULL)
494 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
495 HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
498 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
499 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
500 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
501 surf->aux_ctx = NULL;
502 surf->aux_data = NULL;
503 surf->aux_flip = NULL;
504 break;
507 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
508 IDirectDrawSurfaceImpl *surf2;
509 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
510 for (; surf2 != NULL; surf2 = surf2->next_attached) {
511 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
512 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
513 /* Override the Lock / Unlock function for all these surfaces */
514 surf2->lock_update = surf2->lock_update_prev;
515 surf2->unlock_update = surf2->unlock_update_prev;
516 /* And install also the blt / bltfast overrides */
517 surf2->aux_blt = NULL;
518 surf2->aux_bltfast = NULL;
520 surf2->d3ddevice = NULL;
524 /* And warn the D3D object that this device is no longer active... */
525 This->d3d->d3d_removed_device(This->d3d, This);
527 HeapFree(GetProcessHeap(), 0, This->world_mat);
528 HeapFree(GetProcessHeap(), 0, This->view_mat);
529 HeapFree(GetProcessHeap(), 0, This->proj_mat);
531 if (glThis->surface_ptr)
532 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
534 DeleteCriticalSection(&(This->crit));
536 ENTER_GL();
537 if (glThis->unlock_tex)
538 glDeleteTextures(1, &(glThis->unlock_tex));
539 glXDestroyContext(glThis->display, glThis->gl_context);
540 LEAVE_GL();
541 HeapFree(GetProcessHeap(), 0, This->clipping_planes);
543 HeapFree(GetProcessHeap(), 0, This);
544 return 0;
546 return This->ref;
549 HRESULT WINAPI
550 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
551 LPD3DDEVICEDESC lpD3DHWDevDesc,
552 LPD3DDEVICEDESC lpD3DHELDevDesc)
554 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
555 D3DDEVICEDESC desc;
556 DWORD dwSize;
558 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
560 fill_opengl_caps(&desc);
561 dwSize = lpD3DHWDevDesc->dwSize;
562 memset(lpD3DHWDevDesc, 0, dwSize);
563 memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
565 dwSize = lpD3DHELDevDesc->dwSize;
566 memset(lpD3DHELDevDesc, 0, dwSize);
567 memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
569 TRACE(" returning caps : (no dump function yet)\n");
571 return DD_OK;
574 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
575 LPD3DENUMPIXELFORMATSCALLBACK cb_2,
576 LPVOID context)
578 DDSURFACEDESC sdesc;
579 LPDDPIXELFORMAT pformat;
581 /* Do the texture enumeration */
582 sdesc.dwSize = sizeof(DDSURFACEDESC);
583 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
584 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
585 pformat = &(sdesc.ddpfPixelFormat);
586 pformat->dwSize = sizeof(DDPIXELFORMAT);
587 pformat->dwFourCC = 0;
589 TRACE("Enumerating GL_RGBA unpacked (32)\n");
590 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
591 pformat->u1.dwRGBBitCount = 32;
592 pformat->u2.dwRBitMask = 0x00FF0000;
593 pformat->u3.dwGBitMask = 0x0000FF00;
594 pformat->u4.dwBBitMask = 0x000000FF;
595 pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
596 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
597 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
599 TRACE("Enumerating GL_RGB unpacked (32)\n");
600 pformat->dwFlags = DDPF_RGB;
601 pformat->u1.dwRGBBitCount = 32;
602 pformat->u2.dwRBitMask = 0x00FF0000;
603 pformat->u3.dwGBitMask = 0x0000FF00;
604 pformat->u4.dwBBitMask = 0x000000FF;
605 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
606 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
607 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
609 TRACE("Enumerating GL_RGB unpacked (24)\n");
610 pformat->dwFlags = DDPF_RGB;
611 pformat->u1.dwRGBBitCount = 24;
612 pformat->u2.dwRBitMask = 0x00FF0000;
613 pformat->u3.dwGBitMask = 0x0000FF00;
614 pformat->u4.dwBBitMask = 0x000000FF;
615 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
616 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
617 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
619 /* Note : even if this is an 'emulated' texture format, it needs to be first
620 as some dumb applications seem to rely on that. */
621 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
622 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
623 pformat->u1.dwRGBBitCount = 16;
624 pformat->u2.dwRBitMask = 0x00007C00;
625 pformat->u3.dwGBitMask = 0x000003E0;
626 pformat->u4.dwBBitMask = 0x0000001F;
627 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
628 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
629 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
631 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
632 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
633 pformat->u1.dwRGBBitCount = 16;
634 pformat->u2.dwRBitMask = 0x00000F00;
635 pformat->u3.dwGBitMask = 0x000000F0;
636 pformat->u4.dwBBitMask = 0x0000000F;
637 pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
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 GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
642 pformat->dwFlags = DDPF_RGB;
643 pformat->u1.dwRGBBitCount = 16;
644 pformat->u2.dwRBitMask = 0x0000F800;
645 pformat->u3.dwGBitMask = 0x000007E0;
646 pformat->u4.dwBBitMask = 0x0000001F;
647 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
648 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
649 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
651 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
652 pformat->dwFlags = DDPF_RGB;
653 pformat->u1.dwRGBBitCount = 16;
654 pformat->u2.dwRBitMask = 0x00007C00;
655 pformat->u3.dwGBitMask = 0x000003E0;
656 pformat->u4.dwBBitMask = 0x0000001F;
657 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
658 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
659 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
661 #if 0
662 /* This is a compromise : some games choose the first 16 bit texture format with alpha they
663 find enumerated, others the last one. And both want to have the ARGB one.
665 So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
667 /* See argument about the RGBA format for 'packed' texture formats */
668 TRACE("Enumerating GL_RGBA unpacked (32)\n");
669 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
670 pformat->u1.dwRGBBitCount = 32;
671 pformat->u2.dwRBitMask = 0xFF000000;
672 pformat->u3.dwGBitMask = 0x00FF0000;
673 pformat->u4.dwBBitMask = 0x0000FF00;
674 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
675 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
676 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
678 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
679 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
680 pformat->u1.dwRGBBitCount = 16;
681 pformat->u2.dwRBitMask = 0x0000F000;
682 pformat->u3.dwGBitMask = 0x00000F00;
683 pformat->u4.dwBBitMask = 0x000000F0;
684 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
685 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
686 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
688 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
689 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
690 pformat->u1.dwRGBBitCount = 16;
691 pformat->u2.dwRBitMask = 0x0000F800;
692 pformat->u3.dwGBitMask = 0x000007C0;
693 pformat->u4.dwBBitMask = 0x0000003E;
694 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
695 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
696 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
697 #endif
699 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
700 pformat->dwFlags = DDPF_RGB;
701 pformat->u1.dwRGBBitCount = 8;
702 pformat->u2.dwRBitMask = 0x000000E0;
703 pformat->u3.dwGBitMask = 0x0000001C;
704 pformat->u4.dwBBitMask = 0x00000003;
705 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
706 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
707 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
709 TRACE("Enumerating Paletted (8)\n");
710 pformat->dwFlags = DDPF_PALETTEINDEXED8;
711 pformat->u1.dwRGBBitCount = 8;
712 pformat->u2.dwRBitMask = 0x00000000;
713 pformat->u3.dwGBitMask = 0x00000000;
714 pformat->u4.dwBBitMask = 0x00000000;
715 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
716 if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
717 if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
719 TRACE("End of enumeration\n");
720 return DD_OK;
724 HRESULT
725 d3ddevice_find(IDirectDrawImpl *d3d,
726 LPD3DFINDDEVICESEARCH lpD3DDFS,
727 LPD3DFINDDEVICERESULT lplpD3DDevice)
729 D3DDEVICEDESC desc;
731 if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
732 (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
733 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
734 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
736 if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
737 TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
738 if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
739 (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
740 (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
741 TRACE(" no match for this GUID.\n");
742 return DDERR_INVALIDPARAMS;
746 /* Now return our own GUID */
747 lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
748 fill_opengl_caps(&desc);
749 lplpD3DDevice->ddHwDesc = desc;
750 lplpD3DDevice->ddSwDesc = desc;
752 TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
754 return D3D_OK;
757 HRESULT WINAPI
758 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
759 LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
760 LPVOID lpArg)
762 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
763 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
764 return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg);
767 HRESULT WINAPI
768 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
769 LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
770 LPVOID lpArg)
772 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
773 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
774 return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg);
777 HRESULT WINAPI
778 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
779 D3DRENDERSTATETYPE dwRenderStateType,
780 DWORD dwRenderState)
782 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
783 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
785 /* Call the render state functions */
786 store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
787 set_render_state(This, dwRenderStateType, &This->state_block);
789 return DD_OK;
792 HRESULT WINAPI
793 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
794 D3DRENDERSTATETYPE dwRenderStateType,
795 LPDWORD lpdwRenderState)
797 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
798 TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
800 /* Call the render state functions */
801 get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
803 TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
805 return DD_OK;
808 HRESULT WINAPI
809 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
810 D3DLIGHTSTATETYPE dwLightStateType,
811 DWORD dwLightState)
813 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
815 TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
817 if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX))
818 TRACE("Unexpected Light State Type\n");
819 return DDERR_INVALIDPARAMS;
821 if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
822 IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
824 if (mat != NULL) {
825 mat->activate(mat);
826 } else {
827 ERR(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
829 } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
830 switch (dwLightState) {
831 case D3DCOLOR_MONO:
832 ERR("DDCOLOR_MONO should not happen!\n");
833 break;
834 case D3DCOLOR_RGB:
835 /* We are already in this mode */
836 break;
837 default:
838 ERR("Unknown color model!\n");
839 break;
841 } else {
842 D3DRENDERSTATETYPE rs;
843 switch (dwLightStateType) {
845 case D3DLIGHTSTATE_AMBIENT: /* 2 */
846 rs = D3DRENDERSTATE_AMBIENT;
847 break;
848 case D3DLIGHTSTATE_FOGMODE: /* 4 */
849 rs = D3DRENDERSTATE_FOGVERTEXMODE;
850 break;
851 case D3DLIGHTSTATE_FOGSTART: /* 5 */
852 rs = D3DRENDERSTATE_FOGSTART;
853 break;
854 case D3DLIGHTSTATE_FOGEND: /* 6 */
855 rs = D3DRENDERSTATE_FOGEND;
856 break;
857 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
858 rs = D3DRENDERSTATE_FOGDENSITY;
859 break;
860 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
861 rs = D3DRENDERSTATE_COLORVERTEX;
862 break;
863 default:
864 break;
867 IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
868 rs,dwLightState);
871 return DD_OK;
874 static void draw_primitive_start_GL(D3DPRIMITIVETYPE d3dpt)
876 switch (d3dpt) {
877 case D3DPT_POINTLIST:
878 TRACE("Start POINTS\n");
879 glBegin(GL_POINTS);
880 break;
882 case D3DPT_LINELIST:
883 TRACE("Start LINES\n");
884 glBegin(GL_LINES);
885 break;
887 case D3DPT_LINESTRIP:
888 TRACE("Start LINE_STRIP\n");
889 glBegin(GL_LINE_STRIP);
890 break;
892 case D3DPT_TRIANGLELIST:
893 TRACE("Start TRIANGLES\n");
894 glBegin(GL_TRIANGLES);
895 break;
897 case D3DPT_TRIANGLESTRIP:
898 TRACE("Start TRIANGLE_STRIP\n");
899 glBegin(GL_TRIANGLE_STRIP);
900 break;
902 case D3DPT_TRIANGLEFAN:
903 TRACE("Start TRIANGLE_FAN\n");
904 glBegin(GL_TRIANGLE_FAN);
905 break;
907 default:
908 FIXME("Unhandled primitive %08x\n", d3dpt);
909 break;
913 /* This function calculate the Z coordinate from Zproj */
914 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
916 float a,b,c,d;
917 /* Assume that X = Y = 0 and W = 1 */
918 a = This->proj_mat->_33;
919 b = This->proj_mat->_34;
920 c = This->proj_mat->_43;
921 d = This->proj_mat->_44;
922 /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
923 * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
924 * And finally Z = (d * Zproj - c) / (a - b * Zproj)
926 return (d*Zproj - c) / (a - b*Zproj);
929 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
930 int i;
932 TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
934 for (i = 0; i < 3; i++) {
935 BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
936 DWORD elt;
937 for (elt = 0; elt < 0x10000; elt++) {
938 /* We apply the fog transformation and cache the result */
939 DWORD fog_intensity = elt & 0xFF;
940 DWORD vertex_color = (elt >> 8) & 0xFF;
941 fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
946 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
947 BOOLEAN vertex_transformed,
948 BOOLEAN vertex_lit) {
949 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
951 /* Puts GL in the correct lighting / transformation mode */
952 if ((vertex_transformed == FALSE) &&
953 (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
954 /* Need to put the correct transformation again if we go from Transformed
955 vertices to non-transformed ones.
957 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
958 This->world_mat, This->view_mat, This->proj_mat);
959 glThis->transform_state = GL_TRANSFORM_NORMAL;
961 } else if ((vertex_transformed == TRUE) &&
962 (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
963 /* Set our orthographic projection */
964 if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
965 glThis->transform_state = GL_TRANSFORM_ORTHO;
966 d3ddevice_set_ortho(This);
970 /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
971 if no fogging state change occured */
972 if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
973 if (vertex_transformed == TRUE) {
974 if (glThis->fogging != 0) {
975 glDisable(GL_FOG);
976 glThis->fogging = 0;
978 /* Now check if our fog_table still corresponds to the current vertex color.
979 Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
980 if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
981 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
982 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
983 /* We need to rebuild our fog table.... */
984 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
986 } else {
987 if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
988 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
989 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
990 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
991 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
993 if (vertex_lit == FALSE) {
994 glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
995 glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
996 } else {
997 /* Special case of 'pixel fog' */
998 glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
999 glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
1001 if (glThis->fogging == 0) {
1002 glEnable(GL_FOG);
1003 glThis->fogging = 1;
1005 } else {
1006 if (glThis->fogging != 0) {
1007 glDisable(GL_FOG);
1008 glThis->fogging = 0;
1012 } else {
1013 if (glThis->fogging != 0) {
1014 glDisable(GL_FOG);
1015 glThis->fogging = 0;
1019 /* Handle the 'no-normal' case */
1020 if ((vertex_lit == FALSE) && (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE)) {
1021 if (glThis->lighting == 0) {
1022 glEnable(GL_LIGHTING);
1023 glThis->lighting = 1;
1025 } else {
1026 if (glThis->lighting != 0) {
1027 glDisable(GL_LIGHTING);
1028 glThis->lighting = 0;
1032 /* Handle the code for pre-vertex material properties */
1033 if (vertex_transformed == FALSE) {
1034 if ((This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1035 (This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1036 if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1037 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1038 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1039 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1040 glEnable(GL_COLOR_MATERIAL);
1047 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1048 D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1050 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1052 switch (d3dvt) {
1053 case D3DVT_VERTEX: {
1054 strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1055 strided.position.dwStride = sizeof(D3DVERTEX);
1056 strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1057 strided.normal.dwStride = sizeof(D3DVERTEX);
1058 strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1059 strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1060 draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1061 } break;
1063 case D3DVT_LVERTEX: {
1064 strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1065 strided.position.dwStride = sizeof(D3DLVERTEX);
1066 strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1067 strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1068 strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1069 strided.specular.dwStride = sizeof(D3DLVERTEX);
1070 strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1071 strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1072 draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1073 } break;
1075 case D3DVT_TLVERTEX: {
1076 strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1077 strided.position.dwStride = sizeof(D3DTLVERTEX);
1078 strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1079 strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1080 strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1081 strided.specular.dwStride = sizeof(D3DTLVERTEX);
1082 strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1083 strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1084 draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1085 } break;
1087 default:
1088 FIXME("Unhandled vertex type %08x\n", d3dvt);
1089 break;
1093 HRESULT WINAPI
1094 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1095 D3DPRIMITIVETYPE d3dptPrimitiveType,
1096 D3DVERTEXTYPE d3dvtVertexType,
1097 LPVOID lpvVertices,
1098 DWORD dwVertexCount,
1099 DWORD dwFlags)
1101 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1103 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1104 if (TRACE_ON(ddraw)) {
1105 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1108 draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1110 return DD_OK;
1113 HRESULT WINAPI
1114 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1115 D3DPRIMITIVETYPE d3dptPrimitiveType,
1116 D3DVERTEXTYPE d3dvtVertexType,
1117 LPVOID lpvVertices,
1118 DWORD dwVertexCount,
1119 LPWORD dwIndices,
1120 DWORD dwIndexCount,
1121 DWORD dwFlags)
1123 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1124 TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1125 if (TRACE_ON(ddraw)) {
1126 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1129 draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1131 return DD_OK;
1134 HRESULT WINAPI
1135 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1136 LPD3DEXECUTEBUFFERDESC lpDesc,
1137 LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1138 IUnknown* pUnkOuter)
1140 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1141 IDirect3DExecuteBufferImpl *ret;
1142 HRESULT ret_value;
1144 TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1146 ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1147 *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1149 TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1151 return ret_value;
1154 /* These are the various handler used in the generic path */
1155 inline static void handle_xyz(D3DVALUE *coords) {
1156 glVertex3fv(coords);
1158 inline static void handle_xyzrhw(D3DVALUE *coords) {
1159 if (coords[3] < 1e-8)
1160 glVertex3fv(coords);
1161 else {
1162 GLfloat w = 1.0 / coords[3];
1164 glVertex4f(coords[0] * w,
1165 coords[1] * w,
1166 coords[2] * w,
1170 inline static void handle_normal(D3DVALUE *coords) {
1171 glNormal3fv(coords);
1174 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1175 if ((sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == TRUE) ||
1176 (sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1] == TRUE)) {
1177 glColor4ub((*color >> 16) & 0xFF,
1178 (*color >> 8) & 0xFF,
1179 (*color >> 0) & 0xFF,
1180 (*color >> 24) & 0xFF);
1181 } else {
1182 glColor3ub((*color >> 16) & 0xFF,
1183 (*color >> 8) & 0xFF,
1184 (*color >> 0) & 0xFF);
1188 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1189 glColor4ub((*color >> 16) & 0xFF,
1190 (*color >> 8) & 0xFF,
1191 (*color >> 0) & 0xFF,
1192 (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1195 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1196 if ((lighted == FALSE) &&
1197 (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1198 (sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1199 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1200 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1201 handle_diffuse_base(sb, color);
1203 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1204 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1205 handle_diffuse_base(sb, color);
1207 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1208 (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
1209 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1210 handle_diffuse_base(sb, color);
1212 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1213 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1214 handle_diffuse_base(sb, color);
1216 } else {
1217 handle_diffuse_base(sb, color);
1221 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1222 if ((lighted == FALSE) &&
1223 (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1224 (sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1225 if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1226 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1227 handle_specular_base(sb, color);
1229 if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1230 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1231 handle_specular_base(sb, color);
1233 if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1234 (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
1235 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1236 handle_specular_base(sb, color);
1238 if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1239 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1240 handle_specular_base(sb, color);
1243 /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1246 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1247 if (lighted == TRUE) {
1248 DWORD color = *color_d;
1249 if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
1250 /* Special case where the specular value is used to do fogging */
1251 BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1252 color &= 0xFF000000; /* Only keep the alpha component */
1253 color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
1254 color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
1255 color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1257 if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE) {
1258 /* Standard specular value in transformed mode. TODO */
1260 handle_diffuse_base(sb, &color);
1261 } else {
1262 if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) {
1263 handle_diffuse(sb, color_d, FALSE);
1264 handle_specular(sb, color_s, FALSE);
1265 } else {
1266 /* In that case, only put the diffuse color... */
1267 handle_diffuse_base(sb, color_d);
1272 inline static void handle_texture(D3DVALUE *coords) {
1273 glTexCoord2fv(coords);
1275 inline static void handle_textures(D3DVALUE *coords, int tex_index) {
1276 /* For the moment, draw only the first texture.. */
1277 if (tex_index == 0) glTexCoord2fv(coords);
1280 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1281 D3DPRIMITIVETYPE d3dptPrimitiveType,
1282 DWORD d3dvtVertexType,
1283 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1284 DWORD dwVertexCount,
1285 LPWORD dwIndices,
1286 DWORD dwIndexCount,
1287 DWORD dwFlags)
1289 BOOLEAN vertex_lighted = FALSE;
1290 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1291 int num_active_stages = 0;
1293 /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1294 if (TRACE_ON(ddraw)) {
1295 TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1298 /* This is to prevent 'thread contention' between a thread locking the device and another
1299 doing 3D display on it... */
1300 EnterCriticalSection(&(This->crit));
1302 ENTER_GL();
1303 if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1304 This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1307 glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1309 /* Just a hack for now.. Will have to find better algorithm :-/ */
1310 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
1311 vertex_lighted = TRUE;
1312 } else {
1313 if ((d3dvtVertexType & D3DFVF_NORMAL) == 0) glNormal3f(0.0, 0.0, 0.0);
1316 /* Compute the number of active texture stages and set the various texture parameters */
1317 num_active_stages = draw_primitive_handle_textures(This);
1319 draw_primitive_handle_GL_state(This,
1320 (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1321 vertex_lighted);
1322 draw_primitive_start_GL(d3dptPrimitiveType);
1324 /* Some fast paths first before the generic case.... */
1325 if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1326 int index;
1328 for (index = 0; index < dwIndexCount; index++) {
1329 int i = (dwIndices == NULL) ? index : dwIndices[index];
1330 D3DVALUE *normal =
1331 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1332 D3DVALUE *tex_coord =
1333 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1334 D3DVALUE *position =
1335 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1337 handle_normal(normal);
1338 handle_texture(tex_coord);
1339 handle_xyz(position);
1341 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1342 position[0], position[1], position[2],
1343 normal[0], normal[1], normal[2],
1344 tex_coord[0], tex_coord[1]);
1346 } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1347 int index;
1349 for (index = 0; index < dwIndexCount; index++) {
1350 int i = (dwIndices == NULL) ? index : dwIndices[index];
1351 DWORD *color_d =
1352 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1353 DWORD *color_s =
1354 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1355 D3DVALUE *tex_coord =
1356 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1357 D3DVALUE *position =
1358 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1360 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1361 handle_texture(tex_coord);
1362 handle_xyzrhw(position);
1364 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1365 position[0], position[1], position[2], position[3],
1366 (*color_d >> 16) & 0xFF,
1367 (*color_d >> 8) & 0xFF,
1368 (*color_d >> 0) & 0xFF,
1369 (*color_d >> 24) & 0xFF,
1370 (*color_s >> 16) & 0xFF,
1371 (*color_s >> 8) & 0xFF,
1372 (*color_s >> 0) & 0xFF,
1373 (*color_s >> 24) & 0xFF,
1374 tex_coord[0], tex_coord[1]);
1376 } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1377 ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1378 /* This is the 'slow path' but that should support all possible vertex formats out there...
1379 Note that people should write a fast path for all vertex formats out there...
1381 int index;
1382 int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
1383 static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
1385 for (index = 0; index < dwIndexCount; index++) {
1386 int i = (dwIndices == NULL) ? index : dwIndices[index];
1387 int tex_stage;
1389 if (d3dvtVertexType & D3DFVF_NORMAL) {
1390 D3DVALUE *normal =
1391 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1392 handle_normal(normal);
1394 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1395 DWORD *color_d =
1396 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1397 DWORD *color_s =
1398 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1399 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1400 } else {
1401 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1402 DWORD *color_s =
1403 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1404 handle_specular(&(This->state_block), color_s, vertex_lighted);
1405 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1406 DWORD *color_d =
1407 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1408 handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1412 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1413 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0xFFFF0000;
1414 if (tex_index >= num_tex_index) {
1415 handle_textures((D3DVALUE *) no_index, tex_stage);
1416 } else {
1417 D3DVALUE *tex_coord =
1418 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1419 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1420 handle_textures(tex_coord, tex_stage);
1424 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1425 D3DVALUE *position =
1426 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1427 handle_xyz(position);
1428 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1429 D3DVALUE *position =
1430 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1431 handle_xyzrhw(position);
1434 if (TRACE_ON(ddraw_geom)) {
1435 int tex_index;
1437 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1438 D3DVALUE *position =
1439 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1440 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1441 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1442 D3DVALUE *position =
1443 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1444 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1446 if (d3dvtVertexType & D3DFVF_NORMAL) {
1447 D3DVALUE *normal =
1448 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1449 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1451 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1452 DWORD *color_d =
1453 (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1454 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1455 (*color_d >> 16) & 0xFF,
1456 (*color_d >> 8) & 0xFF,
1457 (*color_d >> 0) & 0xFF,
1458 (*color_d >> 24) & 0xFF);
1460 if (d3dvtVertexType & D3DFVF_SPECULAR) {
1461 DWORD *color_s =
1462 (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1463 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1464 (*color_s >> 16) & 0xFF,
1465 (*color_s >> 8) & 0xFF,
1466 (*color_s >> 0) & 0xFF,
1467 (*color_s >> 24) & 0xFF);
1469 for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
1470 D3DVALUE *tex_coord =
1471 (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
1472 i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1473 TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
1475 TRACE_(ddraw_geom)("\n");
1478 } else {
1479 ERR(" matrix weighting not handled yet....\n");
1482 glEnd();
1484 /* Whatever the case, disable the color material stuff */
1485 glDisable(GL_COLOR_MATERIAL);
1487 LEAVE_GL();
1488 TRACE("End\n");
1490 LeaveCriticalSection(&(This->crit));
1493 HRESULT WINAPI
1494 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1495 D3DPRIMITIVETYPE d3dptPrimitiveType,
1496 DWORD d3dvtVertexType,
1497 LPVOID lpvVertices,
1498 DWORD dwVertexCount,
1499 DWORD dwFlags)
1501 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1502 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1504 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1505 if (TRACE_ON(ddraw)) {
1506 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1509 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1510 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1512 return DD_OK;
1515 HRESULT WINAPI
1516 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1517 D3DPRIMITIVETYPE d3dptPrimitiveType,
1518 DWORD d3dvtVertexType,
1519 LPVOID lpvVertices,
1520 DWORD dwVertexCount,
1521 LPWORD dwIndices,
1522 DWORD dwIndexCount,
1523 DWORD dwFlags)
1525 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1526 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1528 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1529 if (TRACE_ON(ddraw)) {
1530 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1533 convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1534 draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1536 return DD_OK;
1539 HRESULT WINAPI
1540 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1541 D3DPRIMITIVETYPE d3dptPrimitiveType,
1542 DWORD dwVertexType,
1543 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1544 DWORD dwVertexCount,
1545 DWORD dwFlags)
1547 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1549 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1550 if (TRACE_ON(ddraw)) {
1551 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1553 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1555 return DD_OK;
1558 HRESULT WINAPI
1559 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1560 D3DPRIMITIVETYPE d3dptPrimitiveType,
1561 DWORD dwVertexType,
1562 LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1563 DWORD dwVertexCount,
1564 LPWORD lpIndex,
1565 DWORD dwIndexCount,
1566 DWORD dwFlags)
1568 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1570 TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1571 if (TRACE_ON(ddraw)) {
1572 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1575 draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1577 return DD_OK;
1580 HRESULT WINAPI
1581 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1582 D3DPRIMITIVETYPE d3dptPrimitiveType,
1583 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1584 DWORD dwStartVertex,
1585 DWORD dwNumVertices,
1586 DWORD dwFlags)
1588 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1589 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1590 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1592 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1593 if (TRACE_ON(ddraw)) {
1594 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1597 if (vb_impl->processed == TRUE) {
1598 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1599 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1601 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1602 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1603 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1605 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1606 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1608 } else {
1609 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1610 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1613 return DD_OK;
1616 HRESULT WINAPI
1617 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1618 D3DPRIMITIVETYPE d3dptPrimitiveType,
1619 LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1620 DWORD dwStartVertex,
1621 DWORD dwNumVertices,
1622 LPWORD lpwIndices,
1623 DWORD dwIndexCount,
1624 DWORD dwFlags)
1626 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1627 IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1628 D3DDRAWPRIMITIVESTRIDEDDATA strided;
1630 TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1631 if (TRACE_ON(ddraw)) {
1632 TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1635 if (vb_impl->processed == TRUE) {
1636 IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1637 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1639 glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1640 This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1641 &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1643 convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1644 draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1646 } else {
1647 convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1648 draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1651 return DD_OK;
1654 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1655 static BOOLEAN
1656 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1658 BOOLEAN is_complement = FALSE;
1659 BOOLEAN is_alpha_replicate = FALSE;
1660 BOOLEAN handled = TRUE;
1661 GLenum src;
1662 BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1663 int num;
1665 if (is_color) {
1666 if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1667 else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1668 else {
1669 handled = FALSE;
1670 num = 0;
1672 if (tex_op == D3DTOP_SELECTARG2) {
1673 num = 1 - num;
1675 } else {
1676 if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1677 else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1678 else {
1679 handled = FALSE;
1680 num = 0;
1682 if (tex_op == D3DTOP_SELECTARG2) {
1683 num = 1 - num;
1687 if (dwState & D3DTA_COMPLEMENT) {
1688 is_complement = TRUE;
1690 if (dwState & D3DTA_ALPHAREPLICATE) {
1691 is_alpha_replicate = TRUE;
1693 dwState &= D3DTA_SELECTMASK;
1694 if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1695 dwState = D3DTA_DIFFUSE;
1698 switch (dwState) {
1699 case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1700 case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1701 case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1702 case D3DTA_TFACTOR: {
1703 /* Get the constant value from the current rendering state */
1704 GLfloat color[4];
1705 DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1707 color[0] = ((col >> 16) & 0xFF) / 255.0f;
1708 color[1] = ((col >> 8) & 0xFF) / 255.0f;
1709 color[2] = ((col >> 0) & 0xFF) / 255.0f;
1710 color[3] = ((col >> 24) & 0xFF) / 255.0f;
1711 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1713 src = GL_CONSTANT_EXT;
1714 } break;
1715 default: src = GL_TEXTURE; handled = FALSE; break;
1718 if (is_color) {
1719 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1720 if (is_alpha_replicate) {
1721 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1722 } else {
1723 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1725 } else {
1726 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1727 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1730 return handled;
1733 HRESULT WINAPI
1734 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1735 DWORD dwStage,
1736 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1737 DWORD dwState)
1739 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1740 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1741 const char *type;
1742 DWORD prev_state;
1744 TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1746 if (dwStage > 0) return DD_OK; /* We nothing in this case for now */
1748 switch (d3dTexStageStateType) {
1749 #define GEN_CASE(a) case a: type = #a; break
1750 GEN_CASE(D3DTSS_COLOROP);
1751 GEN_CASE(D3DTSS_COLORARG1);
1752 GEN_CASE(D3DTSS_COLORARG2);
1753 GEN_CASE(D3DTSS_ALPHAOP);
1754 GEN_CASE(D3DTSS_ALPHAARG1);
1755 GEN_CASE(D3DTSS_ALPHAARG2);
1756 GEN_CASE(D3DTSS_BUMPENVMAT00);
1757 GEN_CASE(D3DTSS_BUMPENVMAT01);
1758 GEN_CASE(D3DTSS_BUMPENVMAT10);
1759 GEN_CASE(D3DTSS_BUMPENVMAT11);
1760 GEN_CASE(D3DTSS_TEXCOORDINDEX);
1761 GEN_CASE(D3DTSS_ADDRESS);
1762 GEN_CASE(D3DTSS_ADDRESSU);
1763 GEN_CASE(D3DTSS_ADDRESSV);
1764 GEN_CASE(D3DTSS_BORDERCOLOR);
1765 GEN_CASE(D3DTSS_MAGFILTER);
1766 GEN_CASE(D3DTSS_MINFILTER);
1767 GEN_CASE(D3DTSS_MIPFILTER);
1768 GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1769 GEN_CASE(D3DTSS_MAXMIPLEVEL);
1770 GEN_CASE(D3DTSS_MAXANISOTROPY);
1771 GEN_CASE(D3DTSS_BUMPENVLSCALE);
1772 GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1773 GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1774 #undef GEN_CASE
1775 default: type = "UNKNOWN";
1778 /* Store the values in the state array */
1779 prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1780 This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1781 /* Some special cases when one state modifies more than one... */
1782 if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1783 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1784 This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1787 ENTER_GL();
1789 switch (d3dTexStageStateType) {
1790 case D3DTSS_MINFILTER:
1791 case D3DTSS_MIPFILTER:
1792 if (TRACE_ON(ddraw)) {
1793 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1794 switch ((D3DTEXTUREMINFILTER) dwState) {
1795 case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1796 case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1797 default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1799 } else {
1800 switch ((D3DTEXTUREMIPFILTER) dwState) {
1801 case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1802 case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1803 case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1804 default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1808 break;
1810 case D3DTSS_MAGFILTER:
1811 if (TRACE_ON(ddraw)) {
1812 switch ((D3DTEXTUREMAGFILTER) dwState) {
1813 case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_POINT\n"); break;
1814 case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_LINEAR\n"); break;
1815 default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1818 break;
1820 case D3DTSS_ADDRESS:
1821 case D3DTSS_ADDRESSU:
1822 case D3DTSS_ADDRESSV: {
1823 switch ((D3DTEXTUREADDRESS) dwState) {
1824 case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1825 case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1826 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1827 #if defined(GL_VERSION_1_4)
1828 case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); break;
1829 #elif defined(GL_ARB_texture_mirrored_repeat)
1830 case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); break;
1831 #endif
1832 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1834 } break;
1836 case D3DTSS_ALPHAOP:
1837 case D3DTSS_COLOROP: {
1838 int scale = 1;
1839 GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1840 const char *value;
1841 int handled = 1;
1843 switch (dwState) {
1844 #define GEN_CASE(a) case a: value = #a; break
1845 GEN_CASE(D3DTOP_DISABLE);
1846 GEN_CASE(D3DTOP_SELECTARG1);
1847 GEN_CASE(D3DTOP_SELECTARG2);
1848 GEN_CASE(D3DTOP_MODULATE);
1849 GEN_CASE(D3DTOP_MODULATE2X);
1850 GEN_CASE(D3DTOP_MODULATE4X);
1851 GEN_CASE(D3DTOP_ADD);
1852 GEN_CASE(D3DTOP_ADDSIGNED);
1853 GEN_CASE(D3DTOP_ADDSIGNED2X);
1854 GEN_CASE(D3DTOP_SUBTRACT);
1855 GEN_CASE(D3DTOP_ADDSMOOTH);
1856 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1857 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
1858 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
1859 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
1860 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
1861 GEN_CASE(D3DTOP_PREMODULATE);
1862 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
1863 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
1864 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
1865 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
1866 GEN_CASE(D3DTOP_BUMPENVMAP);
1867 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
1868 GEN_CASE(D3DTOP_DOTPRODUCT3);
1869 GEN_CASE(D3DTOP_FORCE_DWORD);
1870 #undef GEN_CASE
1871 default: value = "UNKNOWN";
1874 if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE) && (dwStage == 0)) {
1875 glDisable(GL_TEXTURE_2D);
1876 TRACE(" disabling 2D texturing.\n");
1877 } else {
1878 /* Re-enable texturing */
1879 if ((dwStage == 0) && (This->current_texture[0] != NULL)) {
1880 glEnable(GL_TEXTURE_2D);
1881 TRACE(" enabling 2D texturing.\n");
1884 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
1885 if (dwState != D3DTOP_DISABLE) {
1886 if (glThis->current_tex_env != GL_COMBINE_EXT) {
1887 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1888 glThis->current_tex_env = GL_COMBINE_EXT;
1892 /* Now set up the operand correctly */
1893 switch (dwState) {
1894 case D3DTOP_DISABLE:
1895 /* Contrary to the docs, alpha can be disabled when colorop is enabled
1896 and it works, so ignore this op */
1897 TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
1898 break;
1900 case D3DTOP_SELECTARG1:
1901 case D3DTOP_SELECTARG2:
1902 glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
1903 break;
1905 case D3DTOP_MODULATE4X:
1906 scale = scale * 2; /* Drop through */
1907 case D3DTOP_MODULATE2X:
1908 scale = scale * 2; /* Drop through */
1909 case D3DTOP_MODULATE:
1910 glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
1911 break;
1913 case D3DTOP_ADD:
1914 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
1915 break;
1917 case D3DTOP_ADDSIGNED2X:
1918 scale = scale * 2; /* Drop through */
1919 case D3DTOP_ADDSIGNED:
1920 glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
1921 break;
1923 /* For the four blending modes, use the Arg2 parameter */
1924 case D3DTOP_BLENDDIFFUSEALPHA:
1925 case D3DTOP_BLENDTEXTUREALPHA:
1926 case D3DTOP_BLENDFACTORALPHA:
1927 case D3DTOP_BLENDCURRENTALPHA: {
1928 GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
1930 switch (dwState) {
1931 case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
1932 case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
1933 case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
1934 case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
1937 glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
1938 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
1939 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
1940 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
1941 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
1942 } break;
1944 default:
1945 handled = FALSE;
1946 break;
1950 if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
1951 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
1952 /* Switch the arguments if needed... */
1953 if (d3dTexStageStateType == D3DTSS_COLOROP) {
1954 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
1955 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
1956 dwState);
1957 handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
1958 This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
1959 dwState);
1960 } else {
1961 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
1962 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
1963 dwState);
1964 handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
1965 This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
1966 dwState);
1970 if (handled) {
1971 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
1972 glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
1973 } else {
1974 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
1976 TRACE(" Stage type is : %s => %s\n", type, value);
1977 } else {
1978 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
1980 } break;
1982 case D3DTSS_COLORARG1:
1983 case D3DTSS_COLORARG2:
1984 case D3DTSS_ALPHAARG1:
1985 case D3DTSS_ALPHAARG2: {
1986 const char *value, *value_comp = "", *value_alpha = "";
1987 BOOLEAN handled;
1988 D3DTEXTUREOP tex_op;
1990 switch (dwState & D3DTA_SELECTMASK) {
1991 #define GEN_CASE(a) case a: value = #a; break
1992 GEN_CASE(D3DTA_DIFFUSE);
1993 GEN_CASE(D3DTA_CURRENT);
1994 GEN_CASE(D3DTA_TEXTURE);
1995 GEN_CASE(D3DTA_TFACTOR);
1996 GEN_CASE(D3DTA_SPECULAR);
1997 #undef GEN_CASE
1998 default: value = "UNKNOWN";
2000 if (dwState & D3DTA_COMPLEMENT) {
2001 value_comp = " | D3DTA_COMPLEMENT";
2003 if (dwState & D3DTA_ALPHAREPLICATE) {
2004 value_alpha = " | D3DTA_ALPHAREPLICATE";
2007 if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2008 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2009 } else {
2010 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2013 handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2015 if (handled) {
2016 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2017 } else {
2018 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2020 } break;
2022 case D3DTSS_MIPMAPLODBIAS: {
2023 D3DVALUE value = *((D3DVALUE *) &dwState);
2024 BOOLEAN handled = TRUE;
2026 if (value != 0.0)
2027 handled = FALSE;
2029 if (handled) {
2030 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2031 } else {
2032 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2034 } break;
2036 case D3DTSS_MAXMIPLEVEL:
2037 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2038 break;
2040 case D3DTSS_BORDERCOLOR:
2041 TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2042 ((dwState >> 16) & 0xFF),
2043 ((dwState >> 8) & 0xFF),
2044 ((dwState >> 0) & 0xFF),
2045 ((dwState >> 24) & 0xFF));
2046 break;
2048 case D3DTSS_TEXCOORDINDEX: {
2049 BOOLEAN handled = TRUE;
2050 const char *value;
2052 switch (dwState & 0xFFFF0000) {
2053 #define GEN_CASE(a) case a: value = #a; break
2054 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2055 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2056 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2057 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2058 #undef GEN_CASE
2059 default: value = "UNKNOWN";
2061 if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2062 handled = FALSE;
2064 if (handled) {
2065 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2066 } else {
2067 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2069 } break;
2071 case D3DTSS_TEXTURETRANSFORMFLAGS: {
2072 const char *projected = "", *value;
2073 BOOLEAN handled = TRUE;
2074 switch (dwState & 0xFF) {
2075 #define GEN_CASE(a) case a: value = #a; break
2076 GEN_CASE(D3DTTFF_DISABLE);
2077 GEN_CASE(D3DTTFF_COUNT1);
2078 GEN_CASE(D3DTTFF_COUNT2);
2079 GEN_CASE(D3DTTFF_COUNT3);
2080 GEN_CASE(D3DTTFF_COUNT4);
2081 #undef GEN_CASE
2082 default: value = "UNKNOWN";
2084 if (dwState & D3DTTFF_PROJECTED) {
2085 projected = " | D3DTTFF_PROJECTED";
2086 handled = FALSE;
2089 if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2090 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2093 if (handled == TRUE) {
2094 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2095 } else {
2096 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2098 } break;
2100 default:
2101 FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2102 break;
2105 LEAVE_GL();
2107 return DD_OK;
2110 static DWORD
2111 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2113 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2114 DWORD stage;
2116 for (stage = 0; stage < MAX_TEXTURES; stage++) {
2117 IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2119 /* First check if we need to bind any other texture for this stage */
2120 if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2121 if (This->current_texture[stage] == NULL) {
2122 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2123 glBindTexture(GL_TEXTURE_2D, 0);
2124 glDisable(GL_TEXTURE_2D);
2125 } else {
2126 GLenum tex_name = ((IDirect3DTextureGLImpl *) surf_ptr->tex_private)->tex_name;
2128 if (glThis->current_bound_texture[stage] == NULL) {
2129 if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2130 TRACE(" enabling 2D texturing and");
2131 glEnable(GL_TEXTURE_2D);
2134 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2135 glBindTexture(GL_TEXTURE_2D, tex_name);
2138 glThis->current_bound_texture[stage] = This->current_texture[stage];
2139 } else {
2140 if (glThis->current_bound_texture[stage] == NULL) {
2141 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2142 } else {
2143 TRACE(" using already bound texture id %d for stage %ld.\n",
2144 ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2148 /* If no texure valid for this stage, go out of the loop */
2149 if (This->current_texture[stage] == NULL) break;
2151 /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2152 This will also update the various texture parameters if needed.
2154 gltex_upload_texture(surf_ptr, This, stage);
2157 return stage;
2160 HRESULT WINAPI
2161 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2162 DWORD dwStage,
2163 LPDIRECTDRAWSURFACE7 lpTexture2)
2165 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2167 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2169 if (dwStage > 0) return DD_OK;
2171 if (This->current_texture[dwStage] != NULL) {
2172 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2175 if (lpTexture2 == NULL) {
2176 This->current_texture[dwStage] = NULL;
2177 } else {
2178 IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2179 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2180 This->current_texture[dwStage] = tex_impl;
2183 return DD_OK;
2186 HRESULT WINAPI
2187 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2188 LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2190 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2191 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2193 fill_opengl_caps_7(lpD3DHELDevDesc);
2195 TRACE(" returning caps : no dump function yet.\n");
2197 return DD_OK;
2200 HRESULT WINAPI
2201 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2202 LPD3DMATERIAL7 lpMat)
2204 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2205 TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2207 if (TRACE_ON(ddraw)) {
2208 TRACE(" material is : \n");
2209 dump_D3DMATERIAL7(lpMat);
2212 This->current_material = *lpMat;
2214 ENTER_GL();
2215 glMaterialfv(GL_FRONT_AND_BACK,
2216 GL_DIFFUSE,
2217 (float *) &(This->current_material.u.diffuse));
2218 glMaterialfv(GL_FRONT_AND_BACK,
2219 GL_AMBIENT,
2220 (float *) &(This->current_material.u1.ambient));
2221 glMaterialfv(GL_FRONT_AND_BACK,
2222 GL_SPECULAR,
2223 (float *) &(This->current_material.u2.specular));
2224 glMaterialfv(GL_FRONT_AND_BACK,
2225 GL_EMISSION,
2226 (float *) &(This->current_material.u3.emissive));
2227 glMaterialf(GL_FRONT_AND_BACK,
2228 GL_SHININESS,
2229 This->current_material.u4.power); /* Not sure about this... */
2230 LEAVE_GL();
2232 return DD_OK;
2236 HRESULT WINAPI
2237 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2238 DWORD dwLightIndex,
2239 LPD3DLIGHT7 lpLight)
2241 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2242 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2243 TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2245 if (TRACE_ON(ddraw)) {
2246 TRACE(" setting light : \n");
2247 dump_D3DLIGHT7(lpLight);
2250 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2251 This->set_lights |= 0x00000001 << dwLightIndex;
2252 This->light_parameters[dwLightIndex] = *lpLight;
2254 /* Some checks to print out nice warnings :-) */
2255 switch (lpLight->dltType) {
2256 case D3DLIGHT_DIRECTIONAL:
2257 case D3DLIGHT_POINT:
2258 /* These are handled properly... */
2259 break;
2261 case D3DLIGHT_SPOT:
2262 if ((lpLight->dvTheta != 0.0) ||
2263 (lpLight->dvTheta != lpLight->dvPhi)) {
2264 ERR("dvTheta not fully supported yet !\n");
2266 break;
2268 default:
2269 ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2272 /* This will force the Light setting on next drawing of primitives */
2273 glThis->transform_state = GL_TRANSFORM_NONE;
2275 return DD_OK;
2278 HRESULT WINAPI
2279 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2280 DWORD dwLightIndex,
2281 BOOL bEnable)
2283 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2284 TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2286 if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2288 ENTER_GL();
2289 if (bEnable) {
2290 if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
2291 /* Set the default parameters.. */
2292 TRACE(" setting default light parameters...\n");
2293 GL_IDirect3DDeviceImpl_7_SetLight(iface, dwLightIndex, &(This->light_parameters[dwLightIndex]));
2295 glEnable(GL_LIGHT0 + dwLightIndex);
2296 if ((This->active_lights & (0x00000001 << dwLightIndex)) == 0) {
2297 /* This light gets active... Need to update its parameters to GL before the next drawing */
2298 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2300 This->active_lights |= 0x00000001 << dwLightIndex;
2301 glThis->transform_state = GL_TRANSFORM_NONE;
2303 } else {
2304 glDisable(GL_LIGHT0 + dwLightIndex);
2305 This->active_lights &= ~(0x00000001 << dwLightIndex);
2307 LEAVE_GL();
2309 return DD_OK;
2312 HRESULT WINAPI
2313 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
2315 ICOM_THIS(IDirect3DDeviceImpl,iface);
2316 IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2318 TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2320 if (dwIndex >= This->max_clipping_planes) {
2321 return DDERR_INVALIDPARAMS;
2324 TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2326 memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2328 /* This is to force the reset of the transformation matrices on the next drawing.
2329 * This is needed to use the correct matrices for the various clipping planes.
2331 glThis->transform_state = GL_TRANSFORM_NONE;
2333 return D3D_OK;
2336 HRESULT WINAPI
2337 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2338 LPD3DVIEWPORT7 lpData)
2340 ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2341 TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2343 if (TRACE_ON(ddraw)) {
2344 TRACE(" viewport is : \n");
2345 TRACE(" - dwX = %ld dwY = %ld\n",
2346 lpData->dwX, lpData->dwY);
2347 TRACE(" - dwWidth = %ld dwHeight = %ld\n",
2348 lpData->dwWidth, lpData->dwHeight);
2349 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
2350 lpData->dvMinZ, lpData->dvMaxZ);
2352 ENTER_GL();
2354 /* Set the viewport */
2355 if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2356 (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2357 glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2359 if ((lpData->dwX != This->active_viewport.dwX) ||
2360 (lpData->dwY != This->active_viewport.dwY) ||
2361 (lpData->dwWidth != This->active_viewport.dwWidth) ||
2362 (lpData->dwHeight != This->active_viewport.dwHeight)) {
2363 glViewport(lpData->dwX,
2364 This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2365 lpData->dwWidth, lpData->dwHeight);
2368 LEAVE_GL();
2370 This->active_viewport = *lpData;
2372 return DD_OK;
2375 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2376 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
2377 #else
2378 # define XCAST(fun) (void*)
2379 #endif
2381 ICOM_VTABLE(IDirect3DDevice7) VTABLE_IDirect3DDevice7 =
2383 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2384 XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2385 XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2386 XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2387 XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2388 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2389 XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2390 XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2391 XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2392 XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2393 XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2394 XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2395 XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2396 XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2397 XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2398 XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2399 XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2400 XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2401 XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2402 XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2403 XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2404 XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2405 XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2406 XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2407 XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2408 XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2409 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2410 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2411 XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2412 XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2413 XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2414 XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2415 XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2416 XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2417 XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2418 XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2419 XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2420 XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2421 XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2422 XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2423 XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2424 XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2425 XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2426 XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2427 XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2428 XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2429 XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2430 XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2431 XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2432 XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2435 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2436 #undef XCAST
2437 #endif
2440 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2441 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
2442 #else
2443 # define XCAST(fun) (void*)
2444 #endif
2446 ICOM_VTABLE(IDirect3DDevice3) VTABLE_IDirect3DDevice3 =
2448 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2449 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2450 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2451 XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2452 XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2453 XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2454 XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2455 XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2456 XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2457 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2458 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2459 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2460 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2461 XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2462 XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2463 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2464 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2465 XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2466 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2467 XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2468 XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2469 XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2470 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2471 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2472 XCAST(GetLightState) Main_IDirect3DDeviceImpl_3_2T_GetLightState,
2473 XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2474 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2475 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2476 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2477 XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2478 XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2479 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2480 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2481 XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2482 XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2483 XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2484 XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2485 XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2486 XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2487 XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2488 XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2489 XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2490 XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2493 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2494 #undef XCAST
2495 #endif
2498 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2499 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
2500 #else
2501 # define XCAST(fun) (void*)
2502 #endif
2504 ICOM_VTABLE(IDirect3DDevice2) VTABLE_IDirect3DDevice2 =
2506 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2507 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2508 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2509 XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2510 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2511 XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2512 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2513 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2514 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2515 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2516 XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2517 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2518 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2519 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2520 XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2521 XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2522 XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2523 XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2524 XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2525 XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2526 XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2527 XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2528 XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2529 XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2530 XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2531 XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2532 XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2533 XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2534 XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2535 XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2536 XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2537 XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2538 XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2539 XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2542 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2543 #undef XCAST
2544 #endif
2547 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2548 # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
2549 #else
2550 # define XCAST(fun) (void*)
2551 #endif
2553 ICOM_VTABLE(IDirect3DDevice) VTABLE_IDirect3DDevice =
2555 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2556 XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2557 XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2558 XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2559 XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2560 XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2561 XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2562 XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2563 XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2564 XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2565 XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2566 XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2567 XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2568 XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2569 XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2570 XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2571 XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2572 XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2573 XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2574 XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2575 XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2576 XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2577 XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2580 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2581 #undef XCAST
2582 #endif
2584 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2585 WINE_GL_BUFFER_TYPE buffer_type,
2586 DWORD dwCount,
2587 LPD3DRECT lpRects,
2588 DWORD dwFlags,
2589 DWORD dwColor,
2590 D3DVALUE dvZ,
2591 DWORD dwStencil)
2593 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2594 GLbitfield bitfield = 0;
2595 D3DRECT rect;
2596 int i;
2598 TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2599 if (TRACE_ON(ddraw)) {
2600 if (dwCount > 0) {
2601 int i;
2602 TRACE(" rectangles : \n");
2603 for (i = 0; i < dwCount; i++) {
2604 TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2609 if (dwCount == 0) {
2610 dwCount = 1;
2611 rect.u1.x1 = 0;
2612 rect.u2.y1 = 0;
2613 rect.u3.x2 = This->surface->surface_desc.dwWidth;
2614 rect.u4.y2 = This->surface->surface_desc.dwHeight;
2615 lpRects = &rect;
2618 /* Clears the screen */
2619 ENTER_GL();
2621 if (dwFlags & D3DCLEAR_TARGET) {
2622 if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2623 /* TODO: optimize here the case where Clear changes all the screen... */
2624 This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2626 glThis->state[buffer_type] = SURFACE_GL;
2629 if (dwFlags & D3DCLEAR_ZBUFFER) {
2630 bitfield |= GL_DEPTH_BUFFER_BIT;
2631 if (glThis->depth_mask == FALSE) {
2632 glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2634 if (dvZ != glThis->prev_clear_Z) {
2635 glClearDepth(dvZ);
2636 glThis->prev_clear_Z = dvZ;
2638 TRACE(" depth value : %f\n", dvZ);
2640 if (dwFlags & D3DCLEAR_STENCIL) {
2641 bitfield |= GL_STENCIL_BUFFER_BIT;
2642 if (dwStencil != glThis->prev_clear_stencil) {
2643 glClearStencil(dwStencil);
2644 glThis->prev_clear_stencil = dwStencil;
2646 TRACE(" stencil value : %ld\n", dwStencil);
2648 if (dwFlags & D3DCLEAR_TARGET) {
2649 bitfield |= GL_COLOR_BUFFER_BIT;
2650 if (dwColor != glThis->prev_clear_color) {
2651 glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2652 ((dwColor >> 8) & 0xFF) / 255.0,
2653 ((dwColor >> 0) & 0xFF) / 255.0,
2654 ((dwColor >> 24) & 0xFF) / 255.0);
2655 glThis->prev_clear_color = dwColor;
2657 TRACE(" color value (ARGB) : %08lx\n", dwColor);
2660 glEnable(GL_SCISSOR_TEST);
2661 for (i = 0; i < dwCount; i++) {
2662 glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2663 lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2664 glClear(bitfield);
2666 glDisable(GL_SCISSOR_TEST);
2668 if (dwFlags & D3DCLEAR_ZBUFFER) {
2669 if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2672 LEAVE_GL();
2674 return DD_OK;
2677 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2678 DWORD dwCount,
2679 LPD3DRECT lpRects,
2680 DWORD dwFlags,
2681 DWORD dwColor,
2682 D3DVALUE dvZ,
2683 DWORD dwStencil)
2685 return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2688 static HRESULT
2689 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2690 WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2692 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2693 WINE_GL_BUFFER_TYPE buffer_type;
2695 /* First check if we BLT to the backbuffer... */
2696 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2697 buffer_type = WINE_GL_BUFFER_BACK;
2698 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2699 buffer_type = WINE_GL_BUFFER_FRONT;
2700 } else {
2701 ERR("Only BLT override to front or back-buffer is supported for now !\n");
2702 return DDERR_INVALIDPARAMS;
2705 if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
2706 (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
2707 (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
2708 (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
2709 (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
2710 /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
2711 * GL to do it.
2713 return DDERR_INVALIDPARAMS;
2715 *buffer_type_p = buffer_type;
2717 return DD_OK;
2720 HRESULT
2721 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
2722 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
2723 DWORD dwFlags, LPDDBLTFX lpbltfx)
2725 WINE_GL_BUFFER_TYPE buffer_type;
2726 D3DRECT rect;
2728 if (rdst) {
2729 rect.u1.x1 = rdst->left;
2730 rect.u2.y1 = rdst->top;
2731 rect.u3.x2 = rdst->right;
2732 rect.u4.y2 = rdst->bottom;
2733 } else {
2734 rect.u1.x1 = 0;
2735 rect.u2.y1 = 0;
2736 rect.u3.x2 = This->surface_desc.dwWidth;
2737 rect.u4.y2 = This->surface_desc.dwHeight;
2740 if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
2742 if (dwFlags & DDBLT_COLORFILL) {
2743 /* This is easy to handle for the D3D Device... */
2744 DWORD color;
2745 GLenum prev_draw;
2747 /* The color as given in the Blt function is in the format of the frame-buffer...
2748 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2750 if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
2751 if (This->palette) {
2752 color = ((0xFF000000) |
2753 (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
2754 (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
2755 (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
2756 } else {
2757 color = 0xFF000000;
2759 } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
2760 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
2761 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
2762 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
2763 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
2764 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
2765 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
2766 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
2767 color = 0xFFFFFFFF;
2768 } else {
2769 color = ((0xFF000000) |
2770 ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
2771 ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
2772 ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
2774 } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
2775 (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
2776 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
2777 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
2778 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
2779 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
2780 } else {
2781 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
2782 return DDERR_INVALIDPARAMS;
2784 } else {
2785 ERR("Wrong surface type for BLT override !\n");
2786 return DDERR_INVALIDPARAMS;
2789 TRACE(" executing D3D Device override.\n");
2791 ENTER_GL();
2793 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2794 if (buffer_type == WINE_GL_BUFFER_FRONT)
2795 glDrawBuffer(GL_FRONT);
2796 else
2797 glDrawBuffer(GL_BACK);
2799 d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
2801 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
2802 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
2803 glDrawBuffer(prev_draw);
2805 LEAVE_GL();
2807 return DD_OK;
2808 } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
2809 /* Normal blit without any special case... */
2810 if (src != NULL) {
2811 /* And which has a SRC surface */
2812 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
2814 if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
2815 (src_impl->d3ddevice == This->d3ddevice) &&
2816 ((dwFlags & DDBLT_KEYSRC) == 0)) {
2817 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
2818 D3DRECT src_rect;
2819 int width, height;
2820 GLenum prev_draw;
2821 WINE_GL_BUFFER_TYPE src_buffer_type;
2822 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2823 BOOLEAN initial = FALSE;
2824 DWORD opt_bitmap;
2825 int x, y;
2827 if (rsrc) {
2828 src_rect.u1.x1 = rsrc->left;
2829 src_rect.u2.y1 = rsrc->top;
2830 src_rect.u3.x2 = rsrc->right;
2831 src_rect.u4.y2 = rsrc->bottom;
2832 } else {
2833 src_rect.u1.x1 = 0;
2834 src_rect.u2.y1 = 0;
2835 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
2836 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
2839 width = src_rect.u3.x2 - src_rect.u1.x1;
2840 height = src_rect.u4.y2 - src_rect.u2.y1;
2842 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
2843 (height != (rect.u4.y2 - rect.u2.y1))) {
2844 FIXME(" buffer to buffer copy not supported with stretching yet !\n");
2845 return DDERR_INVALIDPARAMS;
2848 /* First check if we BLT from the backbuffer... */
2849 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2850 src_buffer_type = WINE_GL_BUFFER_BACK;
2851 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2852 src_buffer_type = WINE_GL_BUFFER_FRONT;
2853 } else {
2854 ERR("Unexpected case in direct buffer to buffer copy !\n");
2855 return DDERR_INVALIDPARAMS;
2858 TRACE(" using direct buffer to buffer copy.\n");
2860 ENTER_GL();
2862 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
2864 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
2865 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
2866 ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
2867 LEAVE_GL();
2868 return DDERR_INVALIDPARAMS;
2871 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2872 if (buffer_type == WINE_GL_BUFFER_FRONT)
2873 glDrawBuffer(GL_FRONT);
2874 else
2875 glDrawBuffer(GL_BACK);
2877 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
2878 glReadBuffer(GL_FRONT);
2879 else
2880 glReadBuffer(GL_BACK);
2882 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
2883 And directly re-draws this on the destination buffer. */
2884 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
2885 int get_height;
2887 if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
2888 get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
2889 else
2890 get_height = UNLOCK_TEX_SIZE;
2892 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
2893 int get_width;
2895 if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
2896 get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
2897 else
2898 get_width = UNLOCK_TEX_SIZE;
2900 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2901 0, UNLOCK_TEX_SIZE - get_height,
2902 src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
2903 get_width, get_height);
2905 glBegin(GL_QUADS);
2906 glTexCoord2f(0.0, 0.0);
2907 glVertex3d(rect.u1.x1 + x,
2908 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
2909 0.5);
2910 glTexCoord2f(1.0, 0.0);
2911 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
2912 rect.u2.y1 + y + UNLOCK_TEX_SIZE,
2913 0.5);
2914 glTexCoord2f(1.0, 1.0);
2915 glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
2916 rect.u2.y1 + y,
2917 0.5);
2918 glTexCoord2f(0.0, 1.0);
2919 glVertex3d(rect.u1.x1 + x,
2920 rect.u2.y1 + y,
2921 0.5);
2922 glEnd();
2926 upload_surface_to_tex_memory_release();
2927 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
2929 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
2930 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
2931 glDrawBuffer(prev_draw);
2933 LEAVE_GL();
2935 return DD_OK;
2936 } else {
2937 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
2938 (this prevents calling glReadPixels) */
2939 D3DRECT src_rect;
2940 int width, height;
2941 GLenum prev_draw;
2942 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2943 BOOLEAN initial = FALSE;
2944 DWORD opt_bitmap;
2945 int x, y;
2946 double x_stretch, y_stretch;
2948 if (dwFlags & DDBLT_KEYSRC) {
2949 /* As I have no game using this, did not bother to do it yet as I cannot test it anyway */
2950 FIXME(" Blt overide with color-keying not supported yet.\n");
2951 return DDERR_INVALIDPARAMS;
2954 if (rsrc) {
2955 src_rect.u1.x1 = rsrc->left;
2956 src_rect.u2.y1 = rsrc->top;
2957 src_rect.u3.x2 = rsrc->right;
2958 src_rect.u4.y2 = rsrc->bottom;
2959 } else {
2960 src_rect.u1.x1 = 0;
2961 src_rect.u2.y1 = 0;
2962 src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
2963 src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
2966 width = src_rect.u3.x2 - src_rect.u1.x1;
2967 height = src_rect.u4.y2 - src_rect.u2.y1;
2969 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
2970 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
2972 TRACE(" using memory to buffer Blt overide.\n");
2974 ENTER_GL();
2976 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
2978 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
2979 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
2980 ERR(" unsupported pixel format at memory to buffer Blt overide.\n");
2981 LEAVE_GL();
2982 return DDERR_INVALIDPARAMS;
2985 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2986 if (buffer_type == WINE_GL_BUFFER_FRONT)
2987 glDrawBuffer(GL_FRONT);
2988 else
2989 glDrawBuffer(GL_BACK);
2991 /* Now the serious stuff happens. This is basically the same code that for the memory
2992 flush to frame buffer ... with stretching and different rectangles added :-) */
2993 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
2994 RECT flush_rect;
2996 flush_rect.top = src_rect.u2.y1 + y;
2997 flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
2998 src_rect.u4.y2 :
2999 (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3001 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3002 flush_rect.left = src_rect.u1.x1 + x;
3003 flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3004 src_rect.u3.x2 :
3005 (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3007 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3009 glBegin(GL_QUADS);
3010 glTexCoord2f(0.0, 0.0);
3011 glVertex3d(rect.u1.x1 + (x * x_stretch),
3012 rect.u2.y1 + (y * y_stretch),
3013 0.5);
3014 glTexCoord2f(1.0, 0.0);
3015 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3016 rect.u2.y1 + (y * y_stretch),
3017 0.5);
3018 glTexCoord2f(1.0, 1.0);
3019 glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3020 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3021 0.5);
3022 glTexCoord2f(0.0, 1.0);
3023 glVertex3d(rect.u1.x1 + (x * x_stretch),
3024 rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3025 0.5);
3026 glEnd();
3030 upload_surface_to_tex_memory_release();
3031 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3033 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3034 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3035 glDrawBuffer(prev_draw);
3037 LEAVE_GL();
3039 return DD_OK;
3043 return DDERR_INVALIDPARAMS;
3046 HRESULT
3047 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3048 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3049 LPRECT rsrc, DWORD trans)
3051 RECT rsrc2;
3052 RECT rdst;
3053 IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3054 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3055 WINE_GL_BUFFER_TYPE buffer_type;
3056 GLenum prev_draw;
3057 DWORD opt_bitmap;
3058 BOOLEAN initial;
3059 int width, height, x, y;
3061 /* Cannot support DSTCOLORKEY blitting... */
3062 if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3064 if (rsrc == NULL) {
3065 WARN("rsrc is NULL - getting the whole surface !!\n");
3066 rsrc = &rsrc2;
3067 rsrc->left = rsrc->top = 0;
3068 rsrc->right = src_impl->surface_desc.dwWidth;
3069 rsrc->bottom = src_impl->surface_desc.dwHeight;
3070 } else {
3071 rsrc2 = *rsrc;
3072 rsrc = &rsrc2;
3075 rdst.left = dstx;
3076 rdst.top = dsty;
3077 rdst.right = dstx + (rsrc->right - rsrc->left);
3078 if (rdst.right > This->surface_desc.dwWidth) {
3079 rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3080 rdst.right = This->surface_desc.dwWidth;
3082 rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3083 if (rdst.bottom > This->surface_desc.dwHeight) {
3084 rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3085 rdst.bottom = This->surface_desc.dwHeight;
3088 width = rsrc->right - rsrc->left;
3089 height = rsrc->bottom - rsrc->top;
3091 if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3093 TRACE(" using BltFast memory to frame buffer overide.\n");
3095 ENTER_GL();
3097 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3099 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3100 initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3101 UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3102 ERR(" unsupported pixel format at memory to buffer Blt overide.\n");
3103 LEAVE_GL();
3104 return DDERR_INVALIDPARAMS;
3107 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3108 if (buffer_type == WINE_GL_BUFFER_FRONT)
3109 glDrawBuffer(GL_FRONT);
3110 else
3111 glDrawBuffer(GL_BACK);
3113 /* Now the serious stuff happens. This is basically the same code that for the memory
3114 flush to frame buffer but with different rectangles for source and destination :-) */
3115 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3116 RECT flush_rect;
3118 flush_rect.top = rsrc->top + y;
3119 flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3120 rsrc->bottom :
3121 (rsrc->top + y + UNLOCK_TEX_SIZE));
3123 for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3124 flush_rect.left = rsrc->left + x;
3125 flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3126 rsrc->right :
3127 (rsrc->left + x + UNLOCK_TEX_SIZE));
3129 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3131 glBegin(GL_QUADS);
3132 glTexCoord2f(0.0, 0.0);
3133 glVertex3d(rdst.left + x,
3134 rdst.top + y,
3135 0.5);
3136 glTexCoord2f(1.0, 0.0);
3137 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3138 rdst.top + y,
3139 0.5);
3140 glTexCoord2f(1.0, 1.0);
3141 glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3142 rdst.top + (y + UNLOCK_TEX_SIZE),
3143 0.5);
3144 glTexCoord2f(0.0, 1.0);
3145 glVertex3d(rdst.left + x,
3146 rdst.top + (y + UNLOCK_TEX_SIZE),
3147 0.5);
3148 glEnd();
3152 upload_surface_to_tex_memory_release();
3153 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3155 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3156 ((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
3157 glDrawBuffer(prev_draw);
3159 LEAVE_GL();
3161 return DD_OK;
3164 void
3165 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3167 GLfloat height, width;
3168 GLfloat trans_mat[16];
3170 TRACE("(%p)\n", This);
3172 width = This->surface->surface_desc.dwWidth;
3173 height = This->surface->surface_desc.dwHeight;
3175 /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3176 to OpenGL screen coordinates (ie the upper left corner is not the same).
3177 For Z, the mystery is what should it be mapped to ? Ie should the resulting range be between
3178 -1.0 and 1.0 (as the X and Y coordinates) or between 0.0 and 1.0 ? */
3179 trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
3180 trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
3181 trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = -1.0;
3182 trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
3184 ENTER_GL();
3185 glMatrixMode(GL_MODELVIEW);
3186 glLoadIdentity();
3187 /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3188 Correctness Tips section).
3190 Basically, from what I understood, if the game does not filter the font texture,
3191 as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3192 one and we will have strange artifacts (as the rounding and stuff may give different results
3193 for different pixels, ie sometimes take the left pixel, sometimes the right).
3195 glTranslatef(0.375, 0.375, 0);
3196 glMatrixMode(GL_PROJECTION);
3197 glLoadMatrixf(trans_mat);
3198 LEAVE_GL();
3201 void
3202 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3203 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3205 TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3207 ENTER_GL();
3208 if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3209 glMatrixMode(GL_MODELVIEW);
3210 glLoadMatrixf((float *) view_mat);
3212 /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3213 if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3214 GLint i;
3215 DWORD runner;
3216 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3217 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3218 GLdouble plane[4];
3220 plane[0] = This->clipping_planes[i].plane[0];
3221 plane[1] = This->clipping_planes[i].plane[1];
3222 plane[2] = This->clipping_planes[i].plane[2];
3223 plane[3] = This->clipping_planes[i].plane[3];
3225 glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3229 if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3230 GLint i;
3231 DWORD runner;
3233 for (i = 0, runner = 0x00000001; i < MAX_LIGHTS; i++, runner <<= 1) {
3234 if (runner & This->active_lights) {
3235 switch (This->light_parameters[i].dltType) {
3236 case D3DLIGHT_DIRECTIONAL: {
3237 float direction[4];
3238 float cut_off = 180.0;
3240 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3241 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3242 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3243 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3245 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3246 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3247 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3248 direction[3] = 0.0;
3249 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3250 } break;
3252 case D3DLIGHT_POINT: {
3253 float position[4];
3254 float cut_off = 180.0;
3256 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3257 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3258 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3259 position[0] = This->light_parameters[i].dvPosition.u1.x;
3260 position[1] = This->light_parameters[i].dvPosition.u2.y;
3261 position[2] = This->light_parameters[i].dvPosition.u3.z;
3262 position[3] = 1.0;
3263 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3264 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3265 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3266 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3267 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3268 } break;
3270 case D3DLIGHT_SPOT: {
3271 float direction[4];
3272 float position[4];
3273 float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3275 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
3276 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
3277 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
3279 direction[0] = This->light_parameters[i].dvDirection.u1.x;
3280 direction[1] = This->light_parameters[i].dvDirection.u2.y;
3281 direction[2] = This->light_parameters[i].dvDirection.u3.z;
3282 direction[3] = 0.0;
3283 glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3284 position[0] = This->light_parameters[i].dvPosition.u1.x;
3285 position[1] = This->light_parameters[i].dvPosition.u2.y;
3286 position[2] = This->light_parameters[i].dvPosition.u3.z;
3287 position[3] = 1.0;
3288 glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3289 glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
3290 glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
3291 glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
3292 glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3293 glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &(This->light_parameters[i].dvFalloff));
3294 } break;
3296 default:
3297 /* No warning here as it's already done at light setting */
3298 break;
3304 glMultMatrixf((float *) world_mat);
3306 if ((matrices & PROJMAT_CHANGED) != 0) {
3307 glMatrixMode(GL_PROJECTION);
3308 glLoadMatrixf((float *) proj_mat);
3310 LEAVE_GL();
3313 void
3314 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3316 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3317 DWORD tex_mat, tex_stage;
3319 TRACE("(%p,%08lx)\n", This, matrices);
3321 if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3322 if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3323 /* This will force an update of the transform state at the next drawing. */
3324 glThis->transform_state = GL_TRANSFORM_NONE;
3327 if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3328 TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3330 ENTER_GL();
3331 for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3332 if (matrices & tex_mat) {
3333 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3334 if (tex_stage == 0) {
3335 /* No multi-texturing support for now ... */
3336 glMatrixMode(GL_TEXTURE);
3337 glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3338 if (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE))) {
3339 This->tex_mat_is_identity[tex_stage] = FALSE;
3340 } else {
3341 This->tex_mat_is_identity[tex_stage] = TRUE;
3344 } else {
3345 if (tex_stage == 0) {
3346 if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3347 glMatrixMode(GL_TEXTURE);
3348 glLoadIdentity();
3349 This->tex_mat_is_identity[tex_stage] = TRUE;
3355 LEAVE_GL();
3359 /* TODO for both these functions :
3360 - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3361 by other OpenGL code in D3D
3362 - handle the case where no 'Begin / EndScene' was done between two locks
3363 - handle the rectangles in the unlock too
3364 - handle pitch correctly...
3366 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3368 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3369 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3370 WINE_GL_BUFFER_TYPE buffer_type;
3371 RECT loc_rect;
3373 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3374 buffer_type = WINE_GL_BUFFER_FRONT;
3375 if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3376 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3377 ERR("Change of front buffer.. Expect graphic corruptions !\n");
3379 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3380 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3381 buffer_type = WINE_GL_BUFFER_BACK;
3382 if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3383 (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3384 ERR("Change of back buffer.. Expect graphic corruptions !\n");
3386 gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3387 } else {
3388 ERR("Wrong surface type for locking !\n");
3389 return;
3392 if (pRect == NULL) {
3393 loc_rect.top = 0;
3394 loc_rect.left = 0;
3395 loc_rect.bottom = This->surface_desc.dwHeight;
3396 loc_rect.right = This->surface_desc.dwWidth;
3397 pRect = &loc_rect;
3400 /* Try to acquire the device critical section */
3401 EnterCriticalSection(&(d3d_dev->crit));
3403 if (gl_d3d_dev->lock_rect_valid[buffer_type] == TRUE) {
3404 ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3405 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3407 gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3409 if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3410 /* Check if the new rectangle is in the previous one or not.
3411 If it is not, flush first the previous locks on screen.
3413 if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
3414 (pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
3415 (pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
3416 (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3417 if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3418 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3419 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3420 pRect->left, pRect->top, pRect->right, pRect->bottom,
3421 gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3422 gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3423 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3425 gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3426 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3428 /* In the other case, do not upgrade the locking rectangle as it's no need... */
3429 } else {
3430 gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3433 if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3434 /* If the surface is already in memory, no need to do anything here... */
3435 GLenum buffer_format;
3436 GLenum buffer_color;
3437 int y;
3438 char *dst;
3440 TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3441 pRect->left, pRect->top, pRect->right, pRect->bottom);
3443 /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3444 may only write to the device... But when we will blit it back to the screen, we need
3445 also to blit correctly the parts the application did not overwrite... */
3447 if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3448 (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3449 (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3450 if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3451 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3452 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3453 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3454 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3455 buffer_color = GL_RGB;
3456 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3457 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3458 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3459 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3460 buffer_format = GL_UNSIGNED_BYTE;
3461 buffer_color = GL_RGB;
3462 } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3463 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3464 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3465 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3466 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3467 buffer_color = GL_BGRA;
3468 } else {
3469 ERR(" unsupported pixel format at device locking.\n");
3470 return;
3472 } else {
3473 ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3474 return;
3477 ENTER_GL();
3479 if (buffer_type == WINE_GL_BUFFER_FRONT)
3480 /* Application wants to lock the front buffer */
3481 glReadBuffer(GL_FRONT);
3482 else
3483 /* Application wants to lock the back buffer */
3484 glReadBuffer(GL_BACK);
3486 dst = ((char *)This->surface_desc.lpSurface) +
3487 (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3488 for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3489 y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3490 y--) {
3491 glReadPixels(pRect->left, y,
3492 pRect->right - pRect->left, 1,
3493 buffer_color, buffer_format, dst);
3494 dst += This->surface_desc.u1.lPitch;
3497 gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3499 #if 0
3500 /* I keep this code here as it's very useful to debug :-) */
3502 static int flush_count = 0;
3503 char buf[128];
3504 FILE *f;
3506 if ((++flush_count % 50) == 0) {
3507 sprintf(buf, "lock_%06d.pnm", flush_count);
3508 f = fopen(buf, "wb");
3509 DDRAW_dump_surface_to_disk(This, f);
3512 #endif
3514 LEAVE_GL();
3518 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3519 RECT loc_rect;
3520 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3521 int x, y;
3522 BOOLEAN initial = FALSE;
3523 DWORD opt_bitmap;
3525 /* Note : no need here to lock the 'device critical section' as we are already protected by
3526 the GL critical section. */
3528 if (pRect == NULL) {
3529 loc_rect.top = 0;
3530 loc_rect.left = 0;
3531 loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3532 loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3533 pRect = &loc_rect;
3536 TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3538 opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3540 if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3541 initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3542 ERR(" unsupported pixel format at frame buffer flush.\n");
3543 return;
3546 for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3547 RECT flush_rect;
3549 flush_rect.top = y;
3550 flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3552 for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3553 /* First, upload the texture... */
3554 flush_rect.left = x;
3555 flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
3557 upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3559 glBegin(GL_QUADS);
3560 glTexCoord2f(0.0, 0.0);
3561 glVertex3d(x, y, 0.5);
3562 glTexCoord2f(1.0, 0.0);
3563 glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3564 glTexCoord2f(1.0, 1.0);
3565 glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3566 glTexCoord2f(0.0, 1.0);
3567 glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3568 glEnd();
3572 upload_surface_to_tex_memory_release();
3573 d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3575 #if 0
3576 /* I keep this code here as it's very useful to debug :-) */
3578 static int flush_count = 0;
3579 char buf[128];
3580 FILE *f;
3582 if ((++flush_count % 50) == 0) {
3583 sprintf(buf, "flush_%06d.pnm", flush_count);
3584 f = fopen(buf, "wb");
3585 DDRAW_dump_surface_to_disk(surf, f);
3588 #endif
3591 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3593 WINE_GL_BUFFER_TYPE buffer_type;
3594 IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3595 IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3597 if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3598 buffer_type = WINE_GL_BUFFER_FRONT;
3599 } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3600 buffer_type = WINE_GL_BUFFER_BACK;
3601 } else {
3602 ERR("Wrong surface type for locking !\n");
3603 return;
3606 if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3607 ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3608 (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3610 gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3612 /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3613 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3614 if (buffer_type == WINE_GL_BUFFER_FRONT) {
3615 GLenum prev_draw;
3617 TRACE(" flushing front buffer immediatly on screen.\n");
3619 ENTER_GL();
3620 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3621 glDrawBuffer(GL_FRONT);
3622 /* Note: we do not use the application provided lock rectangle but our own stored at
3623 lock time. This is because in old D3D versions, the 'lock' parameter did not
3624 exist.
3626 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]);
3627 glDrawBuffer(prev_draw);
3628 LEAVE_GL();
3629 } else {
3630 gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3634 /* And 'frees' the device critical section */
3635 LeaveCriticalSection(&(d3d_dev->crit));
3638 static void
3639 apply_texture_state(IDirect3DDeviceImpl *This)
3641 int stage, state;
3643 /* Initialize texture stages states */
3644 for (stage = 0; stage < MAX_TEXTURES; stage++) {
3645 for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3646 if (This->state_block.set_flags.texture_stage_state[stage][state] == TRUE) {
3647 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3648 stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3654 HRESULT
3655 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface)
3657 IDirect3DDeviceImpl *object;
3658 IDirect3DDeviceGLImpl *gl_object;
3659 IDirectDrawSurfaceImpl *surf;
3660 HDC device_context;
3661 XVisualInfo *vis;
3662 int num;
3663 int tex_num;
3664 XVisualInfo template;
3665 GLenum buffer = GL_FRONT;
3666 int light;
3667 GLint max_clipping_planes = 0;
3669 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
3670 if (object == NULL) return DDERR_OUTOFMEMORY;
3672 gl_object = (IDirect3DDeviceGLImpl *) object;
3674 object->ref = 1;
3675 object->d3d = d3d;
3676 object->surface = surface;
3677 object->set_context = set_context;
3678 object->clear = d3ddevice_clear_back;
3679 object->set_matrices = d3ddevice_set_matrices;
3680 object->matrices_updated = d3ddevice_matrices_updated;
3681 object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
3683 TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
3685 InitializeCriticalSection(&(object->crit));
3687 TRACE(" device critical section : %p\n", &(object->crit));
3689 device_context = GetDC(surface->ddraw_owner->window);
3690 gl_object->display = get_display(device_context);
3691 gl_object->drawable = get_drawable(device_context);
3692 ReleaseDC(surface->ddraw_owner->window,device_context);
3694 ENTER_GL();
3695 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
3696 vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
3697 if (vis == NULL) {
3698 HeapFree(GetProcessHeap(), 0, object);
3699 ERR("No visual found !\n");
3700 LEAVE_GL();
3701 return DDERR_INVALIDPARAMS;
3702 } else {
3703 TRACE(" visual found\n");
3706 gl_object->gl_context = glXCreateContext(gl_object->display, vis,
3707 NULL, GL_TRUE);
3709 if (gl_object->gl_context == NULL) {
3710 HeapFree(GetProcessHeap(), 0, object);
3711 ERR("Error in context creation !\n");
3712 LEAVE_GL();
3713 return DDERR_INVALIDPARAMS;
3714 } else {
3715 TRACE(" context created (%p)\n", gl_object->gl_context);
3718 /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
3719 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3720 if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
3721 surf->aux_ctx = (LPVOID) object;
3722 surf->aux_data = (LPVOID) gl_object->drawable;
3723 surf->aux_flip = opengl_flip;
3724 buffer = GL_BACK;
3725 break;
3728 /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
3729 if (surf == NULL) {
3730 TRACE(" no double buffering : drawing on the front buffer\n");
3731 buffer = GL_FRONT;
3734 for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3735 IDirectDrawSurfaceImpl *surf2;
3736 for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
3737 for (; surf2 != NULL; surf2 = surf2->next_attached) {
3738 TRACE(" checking surface %p :", surf2);
3739 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
3740 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
3741 /* Override the Lock / Unlock function for all these surfaces */
3742 surf2->lock_update_prev = surf2->lock_update;
3743 surf2->lock_update = d3ddevice_lock_update;
3744 surf2->unlock_update_prev = surf2->unlock_update;
3745 surf2->unlock_update = d3ddevice_unlock_update;
3746 /* And install also the blt / bltfast overrides */
3747 surf2->aux_blt = d3ddevice_blt;
3748 surf2->aux_bltfast = d3ddevice_bltfast;
3750 TRACE(" overiding direct surface access.\n");
3751 } else {
3752 TRACE(" no overide.\n");
3754 surf2->d3ddevice = object;
3758 /* Set the various light parameters */
3759 for (light = 0; light < MAX_LIGHTS; light++) {
3760 /* Only set the fields that are not zero-created */
3761 object->light_parameters[light].dltType = D3DLIGHT_DIRECTIONAL;
3762 object->light_parameters[light].dcvDiffuse.u1.r = 1.0;
3763 object->light_parameters[light].dcvDiffuse.u2.g = 1.0;
3764 object->light_parameters[light].dcvDiffuse.u3.b = 1.0;
3765 object->light_parameters[light].dvDirection.u3.z = 1.0;
3768 /* Allocate memory for the matrices */
3769 object->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3770 object->view_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3771 object->proj_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3772 memcpy(object->world_mat, id_mat, 16 * sizeof(float));
3773 memcpy(object->view_mat , id_mat, 16 * sizeof(float));
3774 memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
3775 for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
3776 object->tex_mat[tex_num] = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3777 memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
3778 object->tex_mat_is_identity[tex_num] = TRUE;
3781 /* Initialisation */
3782 TRACE(" setting current context\n");
3783 object->set_context(object);
3784 TRACE(" current context set\n");
3786 /* allocate the clipping planes */
3787 glGetIntegerv(GL_MAX_CLIP_PLANES,&max_clipping_planes);
3788 if (max_clipping_planes>32) {
3789 object->max_clipping_planes=32;
3790 } else {
3791 object->max_clipping_planes = max_clipping_planes;
3793 TRACE(" capable of %d clipping planes\n", (int)object->max_clipping_planes );
3794 object->clipping_planes = (d3d7clippingplane*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
3796 glHint(GL_FOG_HINT,GL_NICEST);
3798 /* Initialize the various GL contexts to be in sync with what we store locally */
3799 glClearDepth(0.0);
3800 glClearStencil(0);
3801 glClearColor(0.0, 0.0, 0.0, 0.0);
3802 glDepthMask(GL_TRUE);
3803 gl_object->depth_mask = TRUE;
3804 glEnable(GL_DEPTH_TEST);
3805 gl_object->depth_test = TRUE;
3806 glDisable(GL_ALPHA_TEST);
3807 glDisable(GL_STENCIL_TEST);
3808 glDisable(GL_CULL_FACE);
3809 glDisable(GL_LIGHTING);
3810 glDisable(GL_BLEND);
3811 glDisable(GL_FOG);
3812 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3813 gl_object->current_tex_env = GL_REPLACE;
3815 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3816 glDrawBuffer(buffer);
3817 glReadBuffer(buffer);
3818 /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
3819 LEAVE_GL();
3821 gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
3822 gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
3824 /* fill_device_capabilities(d3d->ddraw); */
3826 ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
3827 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
3828 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
3829 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
3831 *obj = object;
3833 TRACE(" creating implementation at %p.\n", *obj);
3835 /* And finally warn D3D that this device is now present */
3836 object->d3d->d3d_added_device(object->d3d, object);
3838 /* FIXME: Should handle other versions than just 7 */
3839 InitDefaultStateBlock(&object->state_block, 7);
3840 /* Apply default render state and texture stage state values */
3841 apply_render_state(object, &object->state_block);
3842 apply_texture_state(object);
3844 /* And fill the fog table with the default fog value */
3845 build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
3847 return DD_OK;