Added a few C++ operators to Direct3D structures, and made some unions
[wine.git] / dlls / ddraw / d3ddevice / mesa.c
blobde9e888a8fbefe012e7228b9e3be2a150f31ea2f
1 /* Direct3D Device
2 (c) 1998 Lionel ULMER
4 This files contains the MESA implementation of all the D3D devices that
5 Wine supports. */
7 #include <string.h>
8 #include "config.h"
9 #include "windef.h"
10 #include "winerror.h"
11 #include "wine/obj_base.h"
12 #include "heap.h"
13 #include "ddraw.h"
14 #include "d3d.h"
15 #include "debugtools.h"
17 #include "mesa_private.h"
19 DEFAULT_DEBUG_CHANNEL(ddraw)
21 ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable;
22 ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3;
24 /* Define this variable if you have an unpatched Mesa 3.0 (patches are available
25 on Mesa's home page) or version 3.1b.
27 Version 3.1b2 should correct this bug */
28 #undef HAVE_BUGGY_MESAGL
30 #define D3DDPRIVATE(x) mesa_d3dd_private *odev=((mesa_d3dd_private*)x->private)
31 #define DDPRIVATE(x) x11_dd_private *ddpriv=((x11_dd_private*)(x)->d->private)
33 static const float id_mat[16] = {
34 1.0, 0.0, 0.0, 0.0,
35 0.0, 1.0, 0.0, 0.0,
36 0.0, 0.0, 1.0, 0.0,
37 0.0, 0.0, 0.0, 1.0
40 /*******************************************************************************
41 * OpenGL static functions
43 static void set_context(IDirect3DDevice2Impl* This) {
44 D3DDPRIVATE(This);
45 DDPRIVATE(This->surface->s.ddraw);
47 #ifdef USE_OSMESA
48 OSMesaMakeCurrent(d3ddpriv->ctx, odev->buffer, GL_UNSIGNED_BYTE,
49 This->surface->s.surface_desc.dwWidth,
50 This->surface->s.surface_desc.dwHeight);
51 #else
52 if (glXMakeCurrent(display,ddpriv->drawable, odev->ctx) == False) {
53 ERR("Error in setting current context (context %p drawable %ld)!\n",
54 odev->ctx, ddpriv->drawable);
56 #endif
59 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
61 pc->dwSize = sizeof(*pc);
62 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
63 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
64 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
65 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST;
66 pc->dwZCmpCaps = 0xFFFFFFFF; /* All Z test can be done */
67 pc->dwSrcBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
68 pc->dwDestBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
69 pc->dwAlphaCmpCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
70 pc->dwShadeCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
71 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
72 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
73 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
74 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
75 pc->dwTextureBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
76 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP;
77 pc->dwStippleWidth = 32;
78 pc->dwStippleHeight = 32;
81 static void fill_opengl_caps(D3DDEVICEDESC *d1, D3DDEVICEDESC *d2)
83 /* GLint maxlight; */
85 d1->dwSize = sizeof(*d1);
86 d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
87 | D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
88 d1->dcmColorModel = D3DCOLOR_RGB;
89 d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
90 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
91 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
92 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
93 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
94 d1->bClipping = TRUE;
95 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
96 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
97 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
98 d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
99 fill_opengl_primcaps(&(d1->dpcLineCaps));
100 fill_opengl_primcaps(&(d1->dpcTriCaps));
101 d1->dwDeviceRenderBitDepth = DDBD_16;
102 d1->dwDeviceZBufferBitDepth = DDBD_16;
103 d1->dwMaxBufferSize = 0;
104 d1->dwMaxVertexCount = 65536;
105 d1->dwMinTextureWidth = 1;
106 d1->dwMinTextureHeight = 1;
107 d1->dwMaxTextureWidth = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
108 d1->dwMaxTextureHeight = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
109 d1->dwMinStippleWidth = 1;
110 d1->dwMinStippleHeight = 1;
111 d1->dwMaxStippleWidth = 32;
112 d1->dwMaxStippleHeight = 32;
114 d2->dwSize = sizeof(*d2);
115 d2->dwFlags = 0;
118 static void fill_device_capabilities(IDirectDrawImpl* ddraw) {
119 x11_dd_private *private = (x11_dd_private *) ddraw->private;
120 const char *ext_string;
121 Mesa_DeviceCapabilities *devcap;
123 private->device_capabilities = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Mesa_DeviceCapabilities));
124 devcap = (Mesa_DeviceCapabilities *) private->device_capabilities;
126 ENTER_GL();
127 ext_string = glGetString(GL_EXTENSIONS);
128 /* Query for the ColorTable Extension */
129 if (strstr(ext_string, "GL_EXT_paletted_texture")) {
130 devcap->ptr_ColorTableEXT = (PFNGLCOLORTABLEEXTPROC) glXGetProcAddressARB("glColorTableEXT");
131 TRACE("Color table extension supported (function at %p)\n", devcap->ptr_ColorTableEXT);
132 } else {
133 TRACE("Color table extension not found.\n");
135 LEAVE_GL();
138 int d3d_OpenGL(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
139 D3DDEVICEDESC d1,d2;
140 TRACE(" Enumerating OpenGL D3D2 device (IID %s).\n", debugstr_guid(&IID_D3DDEVICE2_OpenGL));
141 fill_opengl_caps(&d1, &d2);
142 return cb((void*)&IID_D3DDEVICE2_OpenGL,"WINE Direct3D2 using OpenGL","direct3d",&d1,&d2,context);
146 is_OpenGL(
147 REFCLSID rguid, IDirectDrawSurfaceImpl* surface,
148 IDirect3DDevice2Impl** device, IDirect3D2Impl* d3d
150 mesa_d3dd_private *odev = NULL;
152 if (/* Default device */
153 (rguid == NULL) ||
154 /* HAL Device */
155 (!memcmp(&IID_IDirect3DHALDevice,rguid,sizeof(IID_IDirect3DHALDevice))) ||
156 /* OpenGL Device */
157 (!memcmp(&IID_D3DDEVICE2_OpenGL,rguid,sizeof(IID_D3DDEVICE2_OpenGL)))) {
159 *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDevice2Impl));
160 (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
161 odev = (mesa_d3dd_private*)(*device)->private;
162 (*device)->ref = 1;
163 ICOM_VTBL(*device) = &OpenGL_vtable;
164 (*device)->d3d = d3d;
165 (*device)->surface = surface;
166 (*device)->viewport_list = NULL;
167 (*device)->current_viewport = NULL;
168 (*device)->set_context = set_context;
170 TRACE("Creating OpenGL device for surface %p\n", surface);
171 /* Create the OpenGL context */
172 #ifdef USE_OSMESA
173 odev->ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
174 odev->buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
175 surface->s.surface_desc.dwWidth * surface->s.surface_desc.dwHeight * 4);
176 #else
177 /* First get the correct visual */
178 ENTER_GL();
179 /* Create the context */
181 XVisualInfo *vis;
182 int num;
183 XVisualInfo template;
185 template.visualid = XVisualIDFromVisual(visual);
186 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
188 odev->ctx = glXCreateContext(display, vis,
189 NULL, GL_TRUE);
192 if (odev->ctx == NULL)
193 ERR("Error in context creation !\n");
194 else
195 TRACE("Context created (%p)\n", odev->ctx);
197 /* Now override the surface's Flip method (if in double buffering) */
198 ((x11_ds_private *) surface->private)->opengl_flip = TRUE;
200 int i;
201 struct _surface_chain *chain = surface->s.chain;
202 for (i=0;i<chain->nrofsurfaces;i++)
203 if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
204 ((x11_ds_private *) chain->surfaces[i]->private)->opengl_flip = TRUE;
207 #endif
208 odev->rs.src = GL_ONE;
209 odev->rs.dst = GL_ZERO;
210 odev->rs.mag = GL_NEAREST;
211 odev->rs.min = GL_NEAREST;
212 odev->vt = 0;
214 /* Allocate memory for the matrices */
215 odev->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
216 odev->view_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
217 odev->proj_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
219 memcpy(odev->world_mat, id_mat, 16 * sizeof(float));
220 memcpy(odev->view_mat , id_mat, 16 * sizeof(float));
221 memcpy(odev->proj_mat , id_mat, 16 * sizeof(float));
223 /* Initialisation */
224 TRACE("Setting current context\n");
225 (*device)->set_context(*device);
226 TRACE("Current context set\n");
227 glClearColor(0.0, 0.0, 0.0, 0.0);
228 glColor3f(1.0, 1.0, 1.0);
229 LEAVE_GL();
231 fill_device_capabilities(d3d->ddraw);
233 TRACE("OpenGL device created \n");
234 return 1;
236 FIXME("bad IID %s\n",debugstr_guid(rguid));
237 /* This is not the OpenGL UID */
238 return 0;
241 /*******************************************************************************
242 * MESA IDirect3DDevice2
244 static ULONG WINAPI MESA_IDirect3DDevice2Impl_Release(LPDIRECT3DDEVICE2 iface)
246 ICOM_THIS(IDirect3DDevice2Impl,iface);
247 D3DDPRIVATE(This);
248 FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
250 if (!--(This->ref)) {
251 #ifdef USE_OSMESA
252 OSMesaDestroyContext(odev->ctx);
253 #else
254 ENTER_GL();
255 glXDestroyContext(display, odev->ctx);
256 LEAVE_GL();
257 #endif
258 This->private = NULL;
259 HeapFree(GetProcessHeap(),0,This);
260 return 0;
262 return This->ref;
265 /*** IDirect3DDevice2 methods ***/
266 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_GetCaps(
267 LPDIRECT3DDEVICE2 iface, LPD3DDEVICEDESC lpdescsoft,
268 LPD3DDEVICEDESC lpdeschard
270 ICOM_THIS(IDirect3DDevice2Impl,iface);
271 FIXME("(%p)->(%p,%p): stub\n", This, lpdescsoft, lpdeschard);
272 fill_opengl_caps(lpdescsoft, lpdeschard);
273 return DD_OK;
276 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb,
277 LPVOID context) {
278 DDSURFACEDESC sdesc;
279 LPDDPIXELFORMAT pformat;
281 /* Do the texture enumeration */
282 sdesc.dwSize = sizeof(DDSURFACEDESC);
283 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
284 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
285 pformat = &(sdesc.ddpfPixelFormat);
286 pformat->dwSize = sizeof(DDPIXELFORMAT);
287 pformat->dwFourCC = 0;
289 TRACE("Enumerating GL_RGBA unpacked (32)\n");
290 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
291 pformat->u.dwRGBBitCount = 32;
292 pformat->u1.dwRBitMask = 0xFF000000;
293 pformat->u2.dwGBitMask = 0x00FF0000;
294 pformat->u3.dwBBitMask = 0x0000FF00;
295 pformat->u4.dwRGBAlphaBitMask = 0x000000FF;
296 if (cb(&sdesc, context) == 0)
297 return DD_OK;
299 TRACE("Enumerating GL_RGB unpacked (24)\n");
300 pformat->dwFlags = DDPF_RGB;
301 pformat->u.dwRGBBitCount = 24;
302 pformat->u1.dwRBitMask = 0x00FF0000;
303 pformat->u2.dwGBitMask = 0x0000FF00;
304 pformat->u3.dwBBitMask = 0x000000FF;
305 pformat->u4.dwRGBAlphaBitMask = 0x00000000;
306 if (cb(&sdesc, context) == 0)
307 return DD_OK;
309 #ifndef HAVE_BUGGY_MESAGL
310 /* The packed texture format are buggy in Mesa. The bug was reported and corrected,
311 so that future version will work great. */
312 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
313 pformat->dwFlags = DDPF_RGB;
314 pformat->u.dwRGBBitCount = 16;
315 pformat->u1.dwRBitMask = 0x0000F800;
316 pformat->u2.dwGBitMask = 0x000007E0;
317 pformat->u3.dwBBitMask = 0x0000001F;
318 pformat->u4.dwRGBAlphaBitMask = 0x00000000;
319 if (cb(&sdesc, context) == 0)
320 return DD_OK;
322 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
323 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
324 pformat->u.dwRGBBitCount = 16;
325 pformat->u1.dwRBitMask = 0x0000F800;
326 pformat->u2.dwGBitMask = 0x000007C0;
327 pformat->u3.dwBBitMask = 0x0000003E;
328 pformat->u4.dwRGBAlphaBitMask = 0x00000001;
329 if (cb(&sdesc, context) == 0)
330 return DD_OK;
332 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
333 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
334 pformat->u.dwRGBBitCount = 16;
335 pformat->u1.dwRBitMask = 0x0000F000;
336 pformat->u2.dwGBitMask = 0x00000F00;
337 pformat->u3.dwBBitMask = 0x000000F0;
338 pformat->u4.dwRGBAlphaBitMask = 0x0000000F;
339 if (cb(&sdesc, context) == 0)
340 return DD_OK;
342 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
343 pformat->dwFlags = DDPF_RGB;
344 pformat->u.dwRGBBitCount = 8;
345 pformat->u1.dwRBitMask = 0x0000F800;
346 pformat->u2.dwGBitMask = 0x000007C0;
347 pformat->u3.dwBBitMask = 0x0000003E;
348 pformat->u4.dwRGBAlphaBitMask = 0x00000001;
349 if (cb(&sdesc, context) == 0)
350 return DD_OK;
351 #endif
353 TRACE("Enumerating Paletted (8)\n");
354 pformat->dwFlags = DDPF_PALETTEINDEXED8;
355 pformat->u.dwRGBBitCount = 8;
356 pformat->u1.dwRBitMask = 0x00000000;
357 pformat->u2.dwGBitMask = 0x00000000;
358 pformat->u3.dwBBitMask = 0x00000000;
359 pformat->u4.dwRGBAlphaBitMask = 0x00000000;
360 if (cb(&sdesc, context) == 0)
361 return DD_OK;
363 TRACE("End of enumeration\n");
365 return DD_OK;
368 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_EnumTextureFormats(
369 LPDIRECT3DDEVICE2 iface, LPD3DENUMTEXTUREFORMATSCALLBACK cb, LPVOID context
371 ICOM_THIS(IDirect3DDevice2Impl,iface);
372 FIXME("(%p)->(%p,%p): stub\n", This, cb, context);
374 return enum_texture_format_OpenGL(cb, context);
377 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_BeginScene(
378 LPDIRECT3DDEVICE2 iface
380 ICOM_THIS(IDirect3DDevice2Impl,iface);
382 FIXME("(%p)->(): stub\n", This);
384 /* Here, we should get the DDraw surface and 'copy it' to the
385 OpenGL surface.... */
387 return DD_OK;
390 HRESULT WINAPI MESA_IDirect3DDevice2Impl_EndScene(LPDIRECT3DDEVICE2 iface) {
391 ICOM_THIS(IDirect3DDevice2Impl,iface);
392 #ifdef USE_OSMESA
393 D3DPRIVATE(This);
395 LPDIRECTDRAWSURFACE3 surf = (LPDIRECTDRAWSURFACE3) This->surface;
396 DDSURFACEDESC sdesc;
397 int x,y;
398 unsigned char *src;
399 unsigned short *dest;
400 #endif
402 FIXME("(%p)->(): stub\n", This);
404 #ifdef USE_OSMESA
405 /* Here we copy back the OpenGL scene to the the DDraw surface */
406 /* First, lock the surface */
407 IDirectDrawSurface3_Lock(surf,NULL,&sdesc,DDLOCK_WRITEONLY,0);
409 /* The copy the OpenGL buffer to this surface */
411 /* NOTE : this is only for debugging purpose. I KNOW it is really unoptimal.
412 I am currently working on a set of patches for Mesa to have OSMesa support
413 16 bpp surfaces => we will able to render directly onto the surface, no
414 need to do a bpp conversion */
415 dest = (unsigned short *) sdesc.y.lpSurface;
416 src = ((unsigned char *) odev->buffer) + 4 * (sdesc.dwWidth * (sdesc.dwHeight - 1));
417 for (y = 0; y < sdesc.dwHeight; y++) {
418 unsigned char *lsrc = src;
420 for (x = 0; x < sdesc.dwWidth ; x++) {
421 unsigned char r = *lsrc++;
422 unsigned char g = *lsrc++;
423 unsigned char b = *lsrc++;
424 lsrc++; /* Alpha */
425 *dest = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
427 dest++;
430 src -= 4 * sdesc.dwWidth;
433 /* Unlock the surface */
434 IDirectDrawSurface3_Unlock(surf,sdesc.y.lpSurface);
435 #else
436 /* No need to do anything here... */
437 #endif
439 return DD_OK;
442 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetRenderState(
443 LPDIRECT3DDEVICE2 iface, D3DRENDERSTATETYPE dwRenderStateType,
444 DWORD dwRenderState
446 ICOM_THIS(IDirect3DDevice2Impl,iface);
447 D3DDPRIVATE(This);
449 TRACE("(%p)->(%d,%ld)\n", This, dwRenderStateType, dwRenderState);
451 /* Call the render state functions */
452 set_render_state(dwRenderStateType, dwRenderState, &(odev->rs));
454 return DD_OK;
457 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetLightState(
458 LPDIRECT3DDEVICE2 iface, D3DLIGHTSTATETYPE dwLightStateType,
459 DWORD dwLightState
461 ICOM_THIS(IDirect3DDevice2Impl,iface);
462 FIXME("(%p)->(%d,%08lx): stub\n", This, dwLightStateType, dwLightState);
464 switch (dwLightStateType) {
465 case D3DLIGHTSTATE_MATERIAL: { /* 1 */
466 IDirect3DMaterial2Impl* mat = (IDirect3DMaterial2Impl*) dwLightState;
468 if (mat != NULL) {
469 ENTER_GL();
470 mat->activate(mat);
471 LEAVE_GL();
472 } else {
473 TRACE("Zoups !!!\n");
475 } break;
477 case D3DLIGHTSTATE_AMBIENT: { /* 2 */
478 float light[4];
480 light[0] = ((dwLightState >> 16) & 0xFF) / 255.0;
481 light[1] = ((dwLightState >> 8) & 0xFF) / 255.0;
482 light[2] = ((dwLightState >> 0) & 0xFF) / 255.0;
483 light[3] = 1.0;
484 ENTER_GL();
485 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
486 LEAVE_GL();
487 } break;
489 #define UNSUP(x) case D3DLIGHTSTATE_##x: FIXME("unsupported D3DLIGHTSTATE_" #x "!\n");break;
490 UNSUP(COLORMODEL);
491 UNSUP(FOGMODE);
492 UNSUP(FOGSTART);
493 UNSUP(FOGEND);
494 UNSUP(FOGDENSITY);
495 #undef UNSUP
496 default:
497 TRACE("Unexpected Light State Type\n");
498 return DDERR_INVALIDPARAMS;
501 return DD_OK;
504 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetTransform(
505 LPDIRECT3DDEVICE2 iface, D3DTRANSFORMSTATETYPE d3dts,
506 LPD3DMATRIX lpmatrix
508 ICOM_THIS(IDirect3DDevice2Impl,iface);
509 D3DDPRIVATE(This);
511 FIXME("(%p)->(%d,%p): stub\n", This, d3dts, lpmatrix);
513 ENTER_GL();
515 /* Using a trial and failure approach, I found that the order of
516 Direct3D transformations that works best is :
518 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
520 As OpenGL uses only two matrices, I combined PROJECTION and VIEW into
521 OpenGL's GL_PROJECTION matrix and the WORLD into GL_MODELVIEW.
523 If anyone has a good explanation of the three different matrices in
524 the SDK online documentation, feel free to point it to me. For example,
525 which matrices transform lights ? In OpenGL only the PROJECTION matrix
526 transform the lights, not the MODELVIEW. Using the matrix names, I
527 supposed that PROJECTION and VIEW (all 'camera' related names) do
528 transform lights, but WORLD do not. It may be wrong though... */
530 /* After reading through both OpenGL and Direct3D documentations, I
531 thought that D3D matrices were written in 'line major mode' transposed
532 from OpenGL's 'column major mode'. But I found out that a simple memcpy
533 works fine to transfer one matrix format to the other (it did not work
534 when transposing)....
536 So :
537 1) are the documentations wrong
538 2) does the matrix work even if they are not read correctly
539 3) is Mesa's implementation of OpenGL not compliant regarding Matrix
540 loading using glLoadMatrix ?
542 Anyway, I always use 'conv_mat' to transfer the matrices from one format
543 to the other so that if I ever find out that I need to transpose them, I
544 will able to do it quickly, only by changing the macro conv_mat. */
546 switch (d3dts) {
547 case D3DTRANSFORMSTATE_WORLD: {
548 conv_mat(lpmatrix, odev->world_mat);
549 glMatrixMode(GL_MODELVIEW);
550 glLoadMatrixf((float *) odev->world_mat);
551 } break;
553 case D3DTRANSFORMSTATE_VIEW: {
554 conv_mat(lpmatrix, odev->view_mat);
555 glMatrixMode(GL_PROJECTION);
556 glLoadMatrixf((float *) odev->proj_mat);
557 glMultMatrixf((float *) odev->view_mat);
558 } break;
560 case D3DTRANSFORMSTATE_PROJECTION: {
561 conv_mat(lpmatrix, odev->proj_mat);
562 glMatrixMode(GL_PROJECTION);
563 glLoadMatrixf((float *) odev->proj_mat);
564 glMultMatrixf((float *) odev->view_mat);
565 } break;
567 default:
568 break;
570 LEAVE_GL();
571 return DD_OK;
574 #define DRAW_PRIMITIVE(MAXVERT,INDEX) \
575 /* Puts GL in the correct lighting mode */ \
576 if (odev->vt != d3dv) { \
577 if (odev->vt == D3DVT_TLVERTEX) { \
578 /* Need to put the correct transformation again */ \
579 glMatrixMode(GL_MODELVIEW); \
580 glLoadMatrixf((float *) odev->world_mat); \
581 glMatrixMode(GL_PROJECTION); \
582 glLoadMatrixf((float *) odev->proj_mat); \
583 glMultMatrixf((float *) odev->view_mat); \
586 switch (d3dv) { \
587 case D3DVT_VERTEX: \
588 TRACE("Standard Vertex\n"); \
589 glEnable(GL_LIGHTING); \
590 break; \
592 case D3DVT_LVERTEX: \
593 TRACE("Lighted Vertex\n"); \
594 glDisable(GL_LIGHTING); \
595 break; \
597 case D3DVT_TLVERTEX: { \
598 GLdouble height, width, minZ, maxZ; \
600 TRACE("Transformed - Lighted Vertex\n"); \
601 /* First, disable lighting */ \
602 glDisable(GL_LIGHTING); \
604 /* Then do not put any transformation matrixes */ \
605 glMatrixMode(GL_MODELVIEW); \
606 glLoadIdentity(); \
607 glMatrixMode(GL_PROJECTION); \
608 glLoadIdentity(); \
610 if (This->current_viewport == NULL) { \
611 ERR("No current viewport !\n"); \
612 /* Using standard values */ \
613 height = 640.0; \
614 width = 480.0; \
615 minZ = -10.0; \
616 maxZ = 10.0; \
617 } else { \
618 if (This->current_viewport->use_vp2) { \
619 height = (GLdouble) This->current_viewport->viewport.vp2.dwHeight;\
620 width = (GLdouble) This->current_viewport->viewport.vp2.dwWidth;\
621 minZ = (GLdouble) This->current_viewport->viewport.vp2.dvMinZ;\
622 maxZ = (GLdouble) This->current_viewport->viewport.vp2.dvMaxZ;\
623 } else { \
624 height = (GLdouble) This->current_viewport->viewport.vp1.dwHeight;\
625 width = (GLdouble) This->current_viewport->viewport.vp1.dwWidth;\
626 minZ = (GLdouble) This->current_viewport->viewport.vp1.dvMinZ;\
627 maxZ = (GLdouble) This->current_viewport->viewport.vp1.dvMaxZ;\
631 glOrtho(0.0, width, height, 0.0, -minZ, -maxZ); \
632 } break; \
634 default: \
635 ERR("Unhandled vertex type\n"); \
636 break; \
639 odev->vt = d3dv; \
642 switch (d3dp) { \
643 case D3DPT_POINTLIST: \
644 TRACE("Start POINTS\n"); \
645 glBegin(GL_POINTS); \
646 break; \
648 case D3DPT_LINELIST: \
649 TRACE("Start LINES\n"); \
650 glBegin(GL_LINES); \
651 break; \
653 case D3DPT_LINESTRIP: \
654 TRACE("Start LINE_STRIP\n"); \
655 glBegin(GL_LINE_STRIP); \
656 break; \
658 case D3DPT_TRIANGLELIST: \
659 TRACE("Start TRIANGLES\n"); \
660 glBegin(GL_TRIANGLES); \
661 break; \
663 case D3DPT_TRIANGLESTRIP: \
664 TRACE("Start TRIANGLE_STRIP\n"); \
665 glBegin(GL_TRIANGLE_STRIP); \
666 break; \
668 case D3DPT_TRIANGLEFAN: \
669 TRACE("Start TRIANGLE_FAN\n"); \
670 glBegin(GL_TRIANGLE_FAN); \
671 break; \
673 default: \
674 TRACE("Unhandled primitive\n"); \
675 break; \
678 /* Draw the primitives */ \
679 for (vx_index = 0; vx_index < MAXVERT; vx_index++) { \
680 switch (d3dv) { \
681 case D3DVT_VERTEX: { \
682 D3DVERTEX *vx = ((D3DVERTEX *) lpvertex) + INDEX; \
684 glNormal3f(vx->nx.nx, vx->ny.ny, vx->nz.nz); \
685 glVertex3f(vx->x.x, vx->y.y, vx->z.z); \
686 TRACE(" V: %f %f %f\n", vx->x.x, vx->y.y, vx->z.z); \
687 } break; \
689 case D3DVT_LVERTEX: { \
690 D3DLVERTEX *vx = ((D3DLVERTEX *) lpvertex) + INDEX; \
691 DWORD col = vx->c.color; \
693 glColor3f(((col >> 16) & 0xFF) / 255.0, \
694 ((col >> 8) & 0xFF) / 255.0, \
695 ((col >> 0) & 0xFF) / 255.0); \
696 glVertex3f(vx->x.x, vx->y.y, vx->z.z); \
697 TRACE(" LV: %f %f %f (%02lx %02lx %02lx)\n", \
698 vx->x.x, vx->y.y, vx->z.z, \
699 ((col >> 16) & 0xFF), ((col >> 8) & 0xFF), ((col >> 0) & 0xFF));\
700 } break; \
702 case D3DVT_TLVERTEX: { \
703 D3DTLVERTEX *vx = ((D3DTLVERTEX *) lpvertex) + INDEX; \
704 DWORD col = vx->c.color; \
706 glColor3f(((col >> 16) & 0xFF) / 255.0, \
707 ((col >> 8) & 0xFF) / 255.0, \
708 ((col >> 0) & 0xFF) / 255.0); \
709 glTexCoord2f(vx->u.tu, vx->v.tv); \
710 if (vx->r.rhw < 0.01) \
711 glVertex3f(vx->x.sx, \
712 vx->y.sy, \
713 vx->z.sz); \
714 else \
715 glVertex4f(vx->x.sx / vx->r.rhw, \
716 vx->y.sy / vx->r.rhw, \
717 vx->z.sz / vx->r.rhw, \
718 1.0 / vx->r.rhw); \
719 TRACE(" TLV: %f %f %f (%02lx %02lx %02lx) (%f %f) (%f)\n", \
720 vx->x.sx, vx->y.sy, vx->z.sz, \
721 ((col >> 16) & 0xFF), ((col >> 8) & 0xFF), ((col >> 0) & 0xFF),\
722 vx->u.tu, vx->v.tv, vx->r.rhw); \
723 } break; \
725 default: \
726 FIXME("Unhandled vertex type\n"); \
727 break; \
731 glEnd(); \
732 TRACE("End\n");
735 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawPrimitive(
736 LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
737 LPVOID lpvertex, DWORD vertcount, DWORD dwFlags
739 ICOM_THIS(IDirect3DDevice2Impl,iface);
740 D3DDPRIVATE(This);
741 int vx_index;
743 TRACE("(%p)->(%d,%d,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, dwFlags);
745 ENTER_GL();
746 DRAW_PRIMITIVE(vertcount, vx_index);
747 LEAVE_GL();
749 return D3D_OK;
752 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive(
753 LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
754 LPVOID lpvertex, DWORD vertcount, LPWORD lpindexes, DWORD indexcount,
755 DWORD dwFlags
757 ICOM_THIS(IDirect3DDevice2Impl,iface);
758 D3DDPRIVATE(This);
759 int vx_index;
761 TRACE("(%p)->(%d,%d,%p,%ld,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, lpindexes, indexcount, dwFlags);
763 ENTER_GL();
764 DRAW_PRIMITIVE(indexcount, lpindexes[vx_index]);
765 LEAVE_GL();
767 return D3D_OK;
770 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_CreateExecuteBuffer(
771 LPDIRECT3DDEVICE iface, LPD3DEXECUTEBUFFERDESC lpDesc,
772 LPDIRECT3DEXECUTEBUFFER *lplpDirect3DExecuteBuffer, IUnknown *pUnkOuter
774 ICOM_THIS(IDirect3DDeviceImpl,iface);
775 TRACE("(%p)->(%p,%p,%p)\n", This, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
776 *lplpDirect3DExecuteBuffer = d3dexecutebuffer_create(This, lpDesc);
777 return DD_OK;
781 /*******************************************************************************
782 * OpenGL-specific IDirect3DDevice2
785 /*******************************************************************************
786 * OpenGL-specific VTable
789 ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable =
791 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
792 IDirect3DDevice2Impl_QueryInterface,
793 IDirect3DDevice2Impl_AddRef,
794 MESA_IDirect3DDevice2Impl_Release,
795 /*** IDirect3DDevice2 methods ***/
796 MESA_IDirect3DDevice2Impl_GetCaps,
797 IDirect3DDevice2Impl_SwapTextureHandles,
798 IDirect3DDevice2Impl_GetStats,
799 IDirect3DDevice2Impl_AddViewport,
800 IDirect3DDevice2Impl_DeleteViewport,
801 IDirect3DDevice2Impl_NextViewport,
802 MESA_IDirect3DDevice2Impl_EnumTextureFormats,
803 MESA_IDirect3DDevice2Impl_BeginScene,
804 MESA_IDirect3DDevice2Impl_EndScene,
805 IDirect3DDevice2Impl_GetDirect3D,
807 /*** DrawPrimitive API ***/
808 IDirect3DDevice2Impl_SetCurrentViewport,
809 IDirect3DDevice2Impl_GetCurrentViewport,
811 IDirect3DDevice2Impl_SetRenderTarget,
812 IDirect3DDevice2Impl_GetRenderTarget,
814 IDirect3DDevice2Impl_Begin,
815 IDirect3DDevice2Impl_BeginIndexed,
816 IDirect3DDevice2Impl_Vertex,
817 IDirect3DDevice2Impl_Index,
818 IDirect3DDevice2Impl_End,
820 IDirect3DDevice2Impl_GetRenderState,
821 MESA_IDirect3DDevice2Impl_SetRenderState,
822 IDirect3DDevice2Impl_GetLightState,
823 MESA_IDirect3DDevice2Impl_SetLightState,
824 MESA_IDirect3DDevice2Impl_SetTransform,
825 IDirect3DDevice2Impl_GetTransform,
826 IDirect3DDevice2Impl_MultiplyTransform,
828 MESA_IDirect3DDevice2Impl_DrawPrimitive,
829 MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive,
831 IDirect3DDevice2Impl_SetClipStatus,
832 IDirect3DDevice2Impl_GetClipStatus,
835 /*******************************************************************************
836 * Direct3DDevice
838 int d3d_OpenGL_dx3(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
839 D3DDEVICEDESC d1,d2;
841 TRACE(" Enumerating OpenGL D3D device (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
843 fill_opengl_caps(&d1, &d2);
845 return cb((void*)&IID_D3DDEVICE_OpenGL,"WINE Direct3D using OpenGL","direct3d",&d1,&d2,context);
848 int is_OpenGL_dx3(REFCLSID rguid, IDirectDrawSurfaceImpl* surface, IDirect3DDeviceImpl** device)
850 if (!memcmp(&IID_D3DDEVICE_OpenGL,rguid,sizeof(IID_D3DDEVICE_OpenGL))) {
851 mesa_d3dd_private *odev;
852 #ifndef USE_OSMESA
853 int attributeList[]={ GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None };
854 XVisualInfo *xvis;
855 #endif
857 *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDeviceImpl));
858 (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
859 odev = (mesa_d3dd_private*)(*device)->private;
860 (*device)->ref = 1;
861 ICOM_VTBL(*device) = &OpenGL_vtable_dx3;
862 (*device)->d3d = NULL;
863 (*device)->surface = surface;
865 (*device)->viewport_list = NULL;
866 (*device)->current_viewport = NULL;
868 (*device)->set_context = (void*)set_context;
870 TRACE("OpenGL device created \n");
872 /* Create the OpenGL context */
873 #ifdef USE_OSMESA
874 odev->ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
875 odev->buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
876 surface->s.surface_desc.dwWidth * surface->s.surface_desc.dwHeight * 4);
877 #else
878 /* First get the correct visual */
879 /* if (surface->s.backbuffer == NULL)
880 attributeList[3] = None; */
881 ENTER_GL();
882 xvis = glXChooseVisual(display,
883 DefaultScreen(display),
884 attributeList);
885 if (xvis == NULL)
886 ERR("No visual found !\n");
887 else
888 TRACE("Visual found\n");
889 /* Create the context */
890 odev->ctx = glXCreateContext(display,
891 xvis,
892 NULL,
893 GL_TRUE);
894 TRACE("Context created\n");
896 #if 0 /* non working currently */
897 /* Now override the surface's Flip method (if in double buffering) */
898 surface->s.d3d_device = (void *) odev;
900 int i;
901 struct _surface_chain *chain = surface->s.chain;
902 for (i=0;i<chain->nrofsurfaces;i++)
903 if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
904 chain->surfaces[i]->s.d3d_device = (void *) odev;
906 #endif
907 #endif
908 odev->rs.src = GL_ONE;
909 odev->rs.dst = GL_ZERO;
910 odev->rs.mag = GL_NEAREST;
911 odev->rs.min = GL_NEAREST;
913 odev->world_mat = (LPD3DMATRIX) &id_mat;
914 odev->view_mat = (LPD3DMATRIX) &id_mat;
915 odev->proj_mat = (LPD3DMATRIX) &id_mat;
917 /* Initialisation */
918 (*device)->set_context(*device);
919 glClearColor(0.0, 0.0, 0.0, 0.0);
920 glColor3f(1.0, 1.0, 1.0);
922 fill_device_capabilities((IDirectDrawImpl *) surface->s.ddraw);
924 return 1;
927 /* This is not the OpenGL UID */
928 return DD_OK;
931 static ULONG WINAPI MESA_IDirect3DDeviceImpl_Release(LPDIRECT3DDEVICE iface)
933 ICOM_THIS(IDirect3DDeviceImpl,iface);
934 FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
936 if (!--(This->ref)) {
937 D3DDPRIVATE(This);
938 #ifdef USE_OSMESA
939 OSMesaDestroyContext(odev->ctx);
940 #else
941 ENTER_GL();
942 glXDestroyContext(display, odev->ctx);
943 LEAVE_GL();
944 #endif
945 This->private = NULL;
946 HeapFree(GetProcessHeap(),0,This);
947 return 0;
949 return This->ref;
952 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EnumTextureFormats(
953 LPDIRECT3DDEVICE iface,LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc,
954 LPVOID lpArg)
956 ICOM_THIS(IDirect3DDeviceImpl,iface);
957 TRACE("(%p)->(%p,%p): stub\n", This, lpd3dEnumTextureProc, lpArg);
959 return enum_texture_format_OpenGL(lpd3dEnumTextureProc, lpArg);
963 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_BeginScene(LPDIRECT3DDEVICE iface)
965 ICOM_THIS(IDirect3DDeviceImpl,iface);
966 /* OpenGL_IDirect3DDevice *odev = (OpenGL_IDirect3DDevice *) This; */
968 FIXME("(%p)->(): stub\n", This);
970 /* We get the pointer to the surface (should be done on flip) */
971 /* odev->zb->pbuf = This->surface->s.surface_desc.y.lpSurface; */
973 return DD_OK;
977 /* This is for the moment copy-pasted from IDirect3DDevice2...
978 Will make a common function ... */
979 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EndScene(LPDIRECT3DDEVICE iface)
981 ICOM_THIS(IDirect3DDeviceImpl,iface);
982 #ifdef USE_OSMESA
983 D3DDPRIVATE(This);
984 LPDIRECTDRAWSURFACE3 surf = (LPDIRECTDRAWSURFACE3) This->surface;
985 DDSURFACEDESC sdesc;
986 int x,y;
987 unsigned char *src;
988 unsigned short *dest;
989 #endif
991 FIXME("(%p)->(): stub\n", This);
993 #ifdef USE_OSMESA
994 /* Here we copy back the OpenGL scene to the the DDraw surface */
995 /* First, lock the surface */
996 IDirectDrawSurface3_Lock(surf,NULL,&sdesc,DDLOCK_WRITEONLY,0);
998 /* The copy the OpenGL buffer to this surface */
1000 /* NOTE : this is only for debugging purpose. I KNOW it is really unoptimal.
1001 I am currently working on a set of patches for Mesa to have OSMesa support
1002 16 bpp surfaces => we will able to render directly onto the surface, no
1003 need to do a bpp conversion */
1004 dest = (unsigned short *) sdesc.y.lpSurface;
1005 src = ((unsigned char *) odev->buffer) + 4 * (sdesc.dwWidth * (sdesc.dwHeight - 1));
1006 for (y = 0; y < sdesc.dwHeight; y++) {
1007 unsigned char *lsrc = src;
1009 for (x = 0; x < sdesc.dwWidth ; x++) {
1010 unsigned char r = *lsrc++;
1011 unsigned char g = *lsrc++;
1012 unsigned char b = *lsrc++;
1013 lsrc++; /* Alpha */
1015 *dest = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1017 dest++;
1020 src -= 4 * sdesc.dwWidth;
1023 /* Unlock the surface */
1024 IDirectDrawSurface3_Unlock(surf,sdesc.y.lpSurface);
1025 #else
1026 /* No need to do anything here... */
1027 #endif
1029 return DD_OK;
1032 /*******************************************************************************
1033 * Direct3DDevice VTable
1035 ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3 =
1037 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1038 IDirect3DDeviceImpl_QueryInterface,
1039 IDirect3DDeviceImpl_AddRef,
1040 MESA_IDirect3DDeviceImpl_Release,
1041 IDirect3DDeviceImpl_Initialize,
1042 IDirect3DDeviceImpl_GetCaps,
1043 IDirect3DDeviceImpl_SwapTextureHandles,
1044 MESA_IDirect3DDeviceImpl_CreateExecuteBuffer,
1045 IDirect3DDeviceImpl_GetStats,
1046 IDirect3DDeviceImpl_Execute,
1047 IDirect3DDeviceImpl_AddViewport,
1048 IDirect3DDeviceImpl_DeleteViewport,
1049 IDirect3DDeviceImpl_NextViewport,
1050 IDirect3DDeviceImpl_Pick,
1051 IDirect3DDeviceImpl_GetPickRecords,
1052 MESA_IDirect3DDeviceImpl_EnumTextureFormats,
1053 IDirect3DDeviceImpl_CreateMatrix,
1054 IDirect3DDeviceImpl_SetMatrix,
1055 IDirect3DDeviceImpl_GetMatrix,
1056 IDirect3DDeviceImpl_DeleteMatrix,
1057 MESA_IDirect3DDeviceImpl_BeginScene,
1058 MESA_IDirect3DDeviceImpl_EndScene,
1059 IDirect3DDeviceImpl_GetDirect3D,