4 This files contains the MESA implementation of all the D3D devices that
11 #include "wine/obj_base.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)
32 #ifndef HAVE_GLEXT_PROTOTYPES
33 /* This is for non-OpenGL ABI compliant glext.h headers :-) */
34 typedef void (* PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat,
35 GLsizei width, GLenum format, GLenum type,
39 static const float id_mat[16] = {
46 /*******************************************************************************
47 * OpenGL static functions
49 static void set_context(IDirect3DDevice2Impl* This) {
54 OSMesaMakeCurrent(d3ddpriv->ctx, odev->buffer, GL_UNSIGNED_BYTE,
55 This->surface->s.surface_desc.dwWidth,
56 This->surface->s.surface_desc.dwHeight);
58 if (glXMakeCurrent(gdi_display,ddpriv->drawable, odev->ctx) == False) {
59 ERR("Error in setting current context (context %p drawable %ld)!\n",
60 odev->ctx, ddpriv->drawable);
66 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
68 pc->dwSize = sizeof(*pc);
69 pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
70 D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
71 pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
72 D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST;
73 pc->dwZCmpCaps = 0xFFFFFFFF; /* All Z test can be done */
74 pc->dwSrcBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
75 pc->dwDestBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
76 pc->dwAlphaCmpCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
77 pc->dwShadeCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
78 pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
79 D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
80 pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
81 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
82 pc->dwTextureBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
83 pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP;
84 pc->dwStippleWidth = 32;
85 pc->dwStippleHeight = 32;
88 static void fill_opengl_caps(D3DDEVICEDESC *d1, D3DDEVICEDESC *d2)
92 d1->dwSize = sizeof(*d1);
93 d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
94 | D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
95 d1->dcmColorModel = D3DCOLOR_RGB;
96 d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
97 D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
98 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
99 d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
100 d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
101 d1->bClipping = TRUE;
102 d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
103 d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
104 d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
105 d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
106 fill_opengl_primcaps(&(d1->dpcLineCaps));
107 fill_opengl_primcaps(&(d1->dpcTriCaps));
108 d1->dwDeviceRenderBitDepth = DDBD_16;
109 d1->dwDeviceZBufferBitDepth = DDBD_16;
110 d1->dwMaxBufferSize = 0;
111 d1->dwMaxVertexCount = 65536;
112 d1->dwMinTextureWidth = 1;
113 d1->dwMinTextureHeight = 1;
114 d1->dwMaxTextureWidth = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
115 d1->dwMaxTextureHeight = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
116 d1->dwMinStippleWidth = 1;
117 d1->dwMinStippleHeight = 1;
118 d1->dwMaxStippleWidth = 32;
119 d1->dwMaxStippleHeight = 32;
121 d2->dwSize = sizeof(*d2);
125 static void fill_device_capabilities(IDirectDrawImpl* ddraw) {
127 x11_dd_private *private = (x11_dd_private *) ddraw->d->private;
128 const char *ext_string;
129 Mesa_DeviceCapabilities *devcap;
131 private->device_capabilities = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Mesa_DeviceCapabilities));
132 devcap = (Mesa_DeviceCapabilities *) private->device_capabilities;
135 ext_string = glGetString(GL_EXTENSIONS);
136 /* Query for the ColorTable Extension */
137 if (strstr(ext_string, "GL_EXT_paletted_texture")) {
138 devcap->ptr_ColorTableEXT = (PFNGLCOLORTABLEEXTPROC) glXGetProcAddressARB("glColorTableEXT");
139 TRACE("Color table extension supported (function at %p)\n", devcap->ptr_ColorTableEXT);
141 TRACE("Color table extension not found.\n");
147 int d3d_OpenGL(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
149 TRACE(" Enumerating OpenGL D3D2 device (IID %s).\n", debugstr_guid(&IID_D3DDEVICE2_OpenGL));
150 fill_opengl_caps(&d1, &d2);
151 return cb((void*)&IID_D3DDEVICE2_OpenGL,"WINE Direct3D2 using OpenGL","direct3d",&d1,&d2,context);
156 REFCLSID rguid, IDirectDrawSurfaceImpl* surface,
157 IDirect3DDevice2Impl** device, IDirect3D2Impl* d3d
159 mesa_d3dd_private *odev = NULL;
161 if (/* Default device */
164 (!memcmp(&IID_IDirect3DHALDevice,rguid,sizeof(IID_IDirect3DHALDevice))) ||
166 (!memcmp(&IID_D3DDEVICE2_OpenGL,rguid,sizeof(IID_D3DDEVICE2_OpenGL)))) {
168 *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDevice2Impl));
169 (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
170 odev = (mesa_d3dd_private*)(*device)->private;
172 ICOM_VTBL(*device) = &OpenGL_vtable;
173 (*device)->d3d = d3d;
174 (*device)->surface = surface;
175 (*device)->viewport_list = NULL;
176 (*device)->current_viewport = NULL;
177 (*device)->set_context = set_context;
179 TRACE("Creating OpenGL device for surface %p\n", surface);
180 /* Create the OpenGL context */
182 odev->ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
183 odev->buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
184 surface->s.surface_desc.dwWidth * surface->s.surface_desc.dwHeight * 4);
186 /* First get the correct visual */
188 /* Create the context */
192 XVisualInfo template;
194 template.visualid = XVisualIDFromVisual(visual);
195 vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
197 odev->ctx = glXCreateContext(gdi_display, vis,
201 if (odev->ctx == NULL)
202 ERR("Error in context creation !\n");
204 TRACE("Context created (%p)\n", odev->ctx);
207 /* Now override the surface's Flip method (if in double buffering) */
208 ((x11_ds_private *) surface->private)->opengl_flip = TRUE;
211 struct _surface_chain *chain = surface->s.chain;
212 for (i=0;i<chain->nrofsurfaces;i++)
213 if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
214 ((x11_ds_private *) chain->surfaces[i]->private)->opengl_flip = TRUE;
219 odev->rs.src = GL_ONE;
220 odev->rs.dst = GL_ZERO;
221 odev->rs.mag = GL_NEAREST;
222 odev->rs.min = GL_NEAREST;
225 /* Allocate memory for the matrices */
226 odev->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
227 odev->view_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
228 odev->proj_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
230 memcpy(odev->world_mat, id_mat, 16 * sizeof(float));
231 memcpy(odev->view_mat , id_mat, 16 * sizeof(float));
232 memcpy(odev->proj_mat , id_mat, 16 * sizeof(float));
235 TRACE("Setting current context\n");
236 (*device)->set_context(*device);
237 TRACE("Current context set\n");
238 glClearColor(0.0, 0.0, 0.0, 0.0);
239 glColor3f(1.0, 1.0, 1.0);
242 fill_device_capabilities(d3d->ddraw);
244 TRACE("OpenGL device created \n");
247 FIXME("bad IID %s\n",debugstr_guid(rguid));
248 /* This is not the OpenGL UID */
252 /*******************************************************************************
253 * MESA IDirect3DDevice2
255 static ULONG WINAPI MESA_IDirect3DDevice2Impl_Release(LPDIRECT3DDEVICE2 iface)
257 ICOM_THIS(IDirect3DDevice2Impl,iface);
259 FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
261 if (!--(This->ref)) {
263 OSMesaDestroyContext(odev->ctx);
266 glXDestroyContext(gdi_display, odev->ctx);
269 This->private = NULL;
270 HeapFree(GetProcessHeap(),0,This);
276 /*** IDirect3DDevice2 methods ***/
277 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_GetCaps(
278 LPDIRECT3DDEVICE2 iface, LPD3DDEVICEDESC lpdescsoft,
279 LPD3DDEVICEDESC lpdeschard
281 ICOM_THIS(IDirect3DDevice2Impl,iface);
282 FIXME("(%p)->(%p,%p): stub\n", This, lpdescsoft, lpdeschard);
283 fill_opengl_caps(lpdescsoft, lpdeschard);
287 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb,
290 LPDDPIXELFORMAT pformat;
292 /* Do the texture enumeration */
293 sdesc.dwSize = sizeof(DDSURFACEDESC);
294 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
295 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
296 pformat = &(sdesc.ddpfPixelFormat);
297 pformat->dwSize = sizeof(DDPIXELFORMAT);
298 pformat->dwFourCC = 0;
300 TRACE("Enumerating GL_RGBA unpacked (32)\n");
301 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
302 pformat->u1.dwRGBBitCount = 32;
303 pformat->u2.dwRBitMask = 0xFF000000;
304 pformat->u3.dwGBitMask = 0x00FF0000;
305 pformat->u4.dwBBitMask = 0x0000FF00;
306 pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
307 if (cb(&sdesc, context) == 0)
310 TRACE("Enumerating GL_RGB unpacked (24)\n");
311 pformat->dwFlags = DDPF_RGB;
312 pformat->u1.dwRGBBitCount = 24;
313 pformat->u2.dwRBitMask = 0x00FF0000;
314 pformat->u3.dwGBitMask = 0x0000FF00;
315 pformat->u4.dwBBitMask = 0x000000FF;
316 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
317 if (cb(&sdesc, context) == 0)
320 #ifndef HAVE_BUGGY_MESAGL
321 /* The packed texture format are buggy in Mesa. The bug was reported and corrected,
322 so that future version will work great. */
323 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
324 pformat->dwFlags = DDPF_RGB;
325 pformat->u1.dwRGBBitCount = 16;
326 pformat->u2.dwRBitMask = 0x0000F800;
327 pformat->u3.dwGBitMask = 0x000007E0;
328 pformat->u4.dwBBitMask = 0x0000001F;
329 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
330 if (cb(&sdesc, context) == 0)
333 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
334 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
335 pformat->u1.dwRGBBitCount = 16;
336 pformat->u2.dwRBitMask = 0x0000F800;
337 pformat->u3.dwGBitMask = 0x000007C0;
338 pformat->u4.dwBBitMask = 0x0000003E;
339 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
340 if (cb(&sdesc, context) == 0)
343 TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
344 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
345 pformat->u1.dwRGBBitCount = 16;
346 pformat->u2.dwRBitMask = 0x0000F000;
347 pformat->u3.dwGBitMask = 0x00000F00;
348 pformat->u4.dwBBitMask = 0x000000F0;
349 pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
350 if (cb(&sdesc, context) == 0)
353 TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
354 pformat->dwFlags = DDPF_RGB;
355 pformat->u1.dwRGBBitCount = 8;
356 pformat->u2.dwRBitMask = 0x0000F800;
357 pformat->u3.dwGBitMask = 0x000007C0;
358 pformat->u4.dwBBitMask = 0x0000003E;
359 pformat->u5.dwRGBAlphaBitMask = 0x00000001;
360 if (cb(&sdesc, context) == 0)
364 TRACE("Enumerating GL_ARGB (no direct OpenGL equivalent - conversion needed)\n");
365 pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
366 pformat->u1.dwRGBBitCount = 16;
367 pformat->u2.dwRBitMask = 0x00007C00;
368 pformat->u3.dwGBitMask = 0x000003E0;
369 pformat->u4.dwBBitMask = 0x0000001F;
370 pformat->u5.dwRGBAlphaBitMask = 0x00008000;
371 if (cb(&sdesc, context) == 0)
374 TRACE("Enumerating Paletted (8)\n");
375 pformat->dwFlags = DDPF_PALETTEINDEXED8;
376 pformat->u1.dwRGBBitCount = 8;
377 pformat->u2.dwRBitMask = 0x00000000;
378 pformat->u3.dwGBitMask = 0x00000000;
379 pformat->u4.dwBBitMask = 0x00000000;
380 pformat->u5.dwRGBAlphaBitMask = 0x00000000;
381 if (cb(&sdesc, context) == 0)
384 TRACE("End of enumeration\n");
389 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_EnumTextureFormats(
390 LPDIRECT3DDEVICE2 iface, LPD3DENUMTEXTUREFORMATSCALLBACK cb, LPVOID context
392 ICOM_THIS(IDirect3DDevice2Impl,iface);
393 FIXME("(%p)->(%p,%p): stub\n", This, cb, context);
395 return enum_texture_format_OpenGL(cb, context);
398 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_BeginScene(
399 LPDIRECT3DDEVICE2 iface
401 ICOM_THIS(IDirect3DDevice2Impl,iface);
403 FIXME("(%p)->(): stub\n", This);
405 /* Here, we should get the DDraw surface and 'copy it' to the
406 OpenGL surface.... */
411 HRESULT WINAPI MESA_IDirect3DDevice2Impl_EndScene(LPDIRECT3DDEVICE2 iface) {
412 ICOM_THIS(IDirect3DDevice2Impl,iface);
416 LPDIRECTDRAWSURFACE3 surf = (LPDIRECTDRAWSURFACE3) This->surface;
420 unsigned short *dest;
423 FIXME("(%p)->(): stub\n", This);
426 /* Here we copy back the OpenGL scene to the the DDraw surface */
427 /* First, lock the surface */
428 IDirectDrawSurface3_Lock(surf,NULL,&sdesc,DDLOCK_WRITEONLY,0);
430 /* The copy the OpenGL buffer to this surface */
432 /* NOTE : this is only for debugging purpose. I KNOW it is really unoptimal.
433 I am currently working on a set of patches for Mesa to have OSMesa support
434 16 bpp surfaces => we will able to render directly onto the surface, no
435 need to do a bpp conversion */
436 dest = (unsigned short *) sdesc.u2.lpSurface;
437 src = ((unsigned char *) odev->buffer) + 4 * (sdesc.dwWidth * (sdesc.dwHeight - 1));
438 for (y = 0; y < sdesc.dwHeight; y++) {
439 unsigned char *lsrc = src;
441 for (x = 0; x < sdesc.dwWidth ; x++) {
442 unsigned char r = *lsrc++;
443 unsigned char g = *lsrc++;
444 unsigned char b = *lsrc++;
446 *dest = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
451 src -= 4 * sdesc.dwWidth;
454 /* Unlock the surface */
455 IDirectDrawSurface3_Unlock(surf,sdesc.u2.lpSurface);
457 /* No need to do anything here... */
463 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetRenderState(
464 LPDIRECT3DDEVICE2 iface, D3DRENDERSTATETYPE dwRenderStateType,
467 ICOM_THIS(IDirect3DDevice2Impl,iface);
470 TRACE("(%p)->(%d,%ld)\n", This, dwRenderStateType, dwRenderState);
472 /* Call the render state functions */
473 set_render_state(dwRenderStateType, dwRenderState, &(odev->rs));
478 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetLightState(
479 LPDIRECT3DDEVICE2 iface, D3DLIGHTSTATETYPE dwLightStateType,
482 ICOM_THIS(IDirect3DDevice2Impl,iface);
483 FIXME("(%p)->(%d,%08lx): stub\n", This, dwLightStateType, dwLightState);
485 switch (dwLightStateType) {
486 case D3DLIGHTSTATE_MATERIAL: { /* 1 */
487 IDirect3DMaterial2Impl* mat = (IDirect3DMaterial2Impl*) dwLightState;
494 TRACE("Zoups !!!\n");
498 case D3DLIGHTSTATE_AMBIENT: { /* 2 */
501 light[0] = ((dwLightState >> 16) & 0xFF) / 255.0;
502 light[1] = ((dwLightState >> 8) & 0xFF) / 255.0;
503 light[2] = ((dwLightState >> 0) & 0xFF) / 255.0;
506 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
510 #define UNSUP(x) case D3DLIGHTSTATE_##x: FIXME("unsupported D3DLIGHTSTATE_" #x "!\n");break;
518 TRACE("Unexpected Light State Type\n");
519 return DDERR_INVALIDPARAMS;
525 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetTransform(
526 LPDIRECT3DDEVICE2 iface, D3DTRANSFORMSTATETYPE d3dts,
529 ICOM_THIS(IDirect3DDevice2Impl,iface);
532 FIXME("(%p)->(%d,%p): stub\n", This, d3dts, lpmatrix);
536 /* Using a trial and failure approach, I found that the order of
537 Direct3D transformations that works best is :
539 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
541 As OpenGL uses only two matrices, I combined PROJECTION and VIEW into
542 OpenGL's GL_PROJECTION matrix and the WORLD into GL_MODELVIEW.
544 If anyone has a good explanation of the three different matrices in
545 the SDK online documentation, feel free to point it to me. For example,
546 which matrices transform lights ? In OpenGL only the PROJECTION matrix
547 transform the lights, not the MODELVIEW. Using the matrix names, I
548 supposed that PROJECTION and VIEW (all 'camera' related names) do
549 transform lights, but WORLD do not. It may be wrong though... */
551 /* After reading through both OpenGL and Direct3D documentations, I
552 thought that D3D matrices were written in 'line major mode' transposed
553 from OpenGL's 'column major mode'. But I found out that a simple memcpy
554 works fine to transfer one matrix format to the other (it did not work
555 when transposing)....
558 1) are the documentations wrong
559 2) does the matrix work even if they are not read correctly
560 3) is Mesa's implementation of OpenGL not compliant regarding Matrix
561 loading using glLoadMatrix ?
563 Anyway, I always use 'conv_mat' to transfer the matrices from one format
564 to the other so that if I ever find out that I need to transpose them, I
565 will able to do it quickly, only by changing the macro conv_mat. */
568 case D3DTRANSFORMSTATE_WORLD: {
569 conv_mat(lpmatrix, odev->world_mat);
570 glMatrixMode(GL_MODELVIEW);
571 glLoadMatrixf((float *) odev->world_mat);
574 case D3DTRANSFORMSTATE_VIEW: {
575 conv_mat(lpmatrix, odev->view_mat);
576 glMatrixMode(GL_PROJECTION);
577 glLoadMatrixf((float *) odev->proj_mat);
578 glMultMatrixf((float *) odev->view_mat);
581 case D3DTRANSFORMSTATE_PROJECTION: {
582 conv_mat(lpmatrix, odev->proj_mat);
583 glMatrixMode(GL_PROJECTION);
584 glLoadMatrixf((float *) odev->proj_mat);
585 glMultMatrixf((float *) odev->view_mat);
595 #define DRAW_PRIMITIVE(MAXVERT,INDEX) \
596 /* Puts GL in the correct lighting mode */ \
597 if (odev->vt != d3dv) { \
598 if (odev->vt == D3DVT_TLVERTEX) { \
599 /* Need to put the correct transformation again */ \
600 glMatrixMode(GL_MODELVIEW); \
601 glLoadMatrixf((float *) odev->world_mat); \
602 glMatrixMode(GL_PROJECTION); \
603 glLoadMatrixf((float *) odev->proj_mat); \
604 glMultMatrixf((float *) odev->view_mat); \
609 TRACE("Standard Vertex\n"); \
610 glEnable(GL_LIGHTING); \
613 case D3DVT_LVERTEX: \
614 TRACE("Lighted Vertex\n"); \
615 glDisable(GL_LIGHTING); \
618 case D3DVT_TLVERTEX: { \
619 GLdouble height, width, minZ, maxZ; \
621 TRACE("Transformed - Lighted Vertex\n"); \
622 /* First, disable lighting */ \
623 glDisable(GL_LIGHTING); \
625 /* Then do not put any transformation matrixes */ \
626 glMatrixMode(GL_MODELVIEW); \
628 glMatrixMode(GL_PROJECTION); \
631 if (This->current_viewport == NULL) { \
632 ERR("No current viewport !\n"); \
633 /* Using standard values */ \
639 if (This->current_viewport->use_vp2) { \
640 height = (GLdouble) This->current_viewport->viewport.vp2.dwHeight;\
641 width = (GLdouble) This->current_viewport->viewport.vp2.dwWidth;\
642 minZ = (GLdouble) This->current_viewport->viewport.vp2.dvMinZ;\
643 maxZ = (GLdouble) This->current_viewport->viewport.vp2.dvMaxZ;\
645 height = (GLdouble) This->current_viewport->viewport.vp1.dwHeight;\
646 width = (GLdouble) This->current_viewport->viewport.vp1.dwWidth;\
647 minZ = (GLdouble) This->current_viewport->viewport.vp1.dvMinZ;\
648 maxZ = (GLdouble) This->current_viewport->viewport.vp1.dvMaxZ;\
652 glOrtho(0.0, width, height, 0.0, -minZ, -maxZ); \
656 ERR("Unhandled vertex type\n"); \
664 case D3DPT_POINTLIST: \
665 TRACE("Start POINTS\n"); \
666 glBegin(GL_POINTS); \
669 case D3DPT_LINELIST: \
670 TRACE("Start LINES\n"); \
674 case D3DPT_LINESTRIP: \
675 TRACE("Start LINE_STRIP\n"); \
676 glBegin(GL_LINE_STRIP); \
679 case D3DPT_TRIANGLELIST: \
680 TRACE("Start TRIANGLES\n"); \
681 glBegin(GL_TRIANGLES); \
684 case D3DPT_TRIANGLESTRIP: \
685 TRACE("Start TRIANGLE_STRIP\n"); \
686 glBegin(GL_TRIANGLE_STRIP); \
689 case D3DPT_TRIANGLEFAN: \
690 TRACE("Start TRIANGLE_FAN\n"); \
691 glBegin(GL_TRIANGLE_FAN); \
695 TRACE("Unhandled primitive\n"); \
699 /* Draw the primitives */ \
700 for (vx_index = 0; vx_index < MAXVERT; vx_index++) { \
702 case D3DVT_VERTEX: { \
703 D3DVERTEX *vx = ((D3DVERTEX *) lpvertex) + INDEX; \
705 glNormal3f(vx->u4.nx, vx->u5.ny, vx->u6.nz); \
706 glVertex3f(vx->u1.x, vx->u2.y, vx->u3.z); \
707 TRACE(" V: %f %f %f\n", vx->u1.x, vx->u2.y, vx->u3.z); \
710 case D3DVT_LVERTEX: { \
711 D3DLVERTEX *vx = ((D3DLVERTEX *) lpvertex) + INDEX; \
712 DWORD col = vx->u4.color; \
714 glColor3f(((col >> 16) & 0xFF) / 255.0, \
715 ((col >> 8) & 0xFF) / 255.0, \
716 ((col >> 0) & 0xFF) / 255.0); \
717 glVertex3f(vx->u1.x, vx->u2.y, vx->u3.z); \
718 TRACE(" LV: %f %f %f (%02lx %02lx %02lx)\n", \
719 vx->u1.x, vx->u2.y, vx->u3.z, \
720 ((col >> 16) & 0xFF), ((col >> 8) & 0xFF), ((col >> 0) & 0xFF));\
723 case D3DVT_TLVERTEX: { \
724 D3DTLVERTEX *vx = ((D3DTLVERTEX *) lpvertex) + INDEX; \
725 DWORD col = vx->u5.color; \
727 glColor3f(((col >> 16) & 0xFF) / 255.0, \
728 ((col >> 8) & 0xFF) / 255.0, \
729 ((col >> 0) & 0xFF) / 255.0); \
730 glTexCoord2f(vx->u7.tu, vx->u8.tv); \
731 if (vx->u4.rhw < 0.01) \
732 glVertex3f(vx->u1.sx, \
736 glVertex4f(vx->u1.sx / vx->u4.rhw, \
737 vx->u2.sy / vx->u4.rhw, \
738 vx->u3.sz / vx->u4.rhw, \
740 TRACE(" TLV: %f %f %f (%02lx %02lx %02lx) (%f %f) (%f)\n", \
741 vx->u1.sx, vx->u2.sy, vx->u3.sz, \
742 ((col >> 16) & 0xFF), ((col >> 8) & 0xFF), ((col >> 0) & 0xFF),\
743 vx->u7.tu, vx->u8.tv, vx->u4.rhw); \
747 FIXME("Unhandled vertex type\n"); \
756 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawPrimitive(
757 LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
758 LPVOID lpvertex, DWORD vertcount, DWORD dwFlags
760 ICOM_THIS(IDirect3DDevice2Impl,iface);
764 TRACE("(%p)->(%d,%d,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, dwFlags);
767 DRAW_PRIMITIVE(vertcount, vx_index);
773 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive(
774 LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
775 LPVOID lpvertex, DWORD vertcount, LPWORD lpindexes, DWORD indexcount,
778 ICOM_THIS(IDirect3DDevice2Impl,iface);
782 TRACE("(%p)->(%d,%d,%p,%ld,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, lpindexes, indexcount, dwFlags);
785 DRAW_PRIMITIVE(indexcount, lpindexes[vx_index]);
791 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_CreateExecuteBuffer(
792 LPDIRECT3DDEVICE iface, LPD3DEXECUTEBUFFERDESC lpDesc,
793 LPDIRECT3DEXECUTEBUFFER *lplpDirect3DExecuteBuffer, IUnknown *pUnkOuter
795 ICOM_THIS(IDirect3DDeviceImpl,iface);
796 TRACE("(%p)->(%p,%p,%p)\n", This, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
797 *lplpDirect3DExecuteBuffer = d3dexecutebuffer_create(This, lpDesc);
802 /*******************************************************************************
803 * OpenGL-specific IDirect3DDevice2
806 /*******************************************************************************
807 * OpenGL-specific VTable
810 ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable =
812 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
813 IDirect3DDevice2Impl_QueryInterface,
814 IDirect3DDevice2Impl_AddRef,
815 MESA_IDirect3DDevice2Impl_Release,
816 /*** IDirect3DDevice2 methods ***/
817 MESA_IDirect3DDevice2Impl_GetCaps,
818 IDirect3DDevice2Impl_SwapTextureHandles,
819 IDirect3DDevice2Impl_GetStats,
820 IDirect3DDevice2Impl_AddViewport,
821 IDirect3DDevice2Impl_DeleteViewport,
822 IDirect3DDevice2Impl_NextViewport,
823 MESA_IDirect3DDevice2Impl_EnumTextureFormats,
824 MESA_IDirect3DDevice2Impl_BeginScene,
825 MESA_IDirect3DDevice2Impl_EndScene,
826 IDirect3DDevice2Impl_GetDirect3D,
828 /*** DrawPrimitive API ***/
829 IDirect3DDevice2Impl_SetCurrentViewport,
830 IDirect3DDevice2Impl_GetCurrentViewport,
832 IDirect3DDevice2Impl_SetRenderTarget,
833 IDirect3DDevice2Impl_GetRenderTarget,
835 IDirect3DDevice2Impl_Begin,
836 IDirect3DDevice2Impl_BeginIndexed,
837 IDirect3DDevice2Impl_Vertex,
838 IDirect3DDevice2Impl_Index,
839 IDirect3DDevice2Impl_End,
841 IDirect3DDevice2Impl_GetRenderState,
842 MESA_IDirect3DDevice2Impl_SetRenderState,
843 IDirect3DDevice2Impl_GetLightState,
844 MESA_IDirect3DDevice2Impl_SetLightState,
845 MESA_IDirect3DDevice2Impl_SetTransform,
846 IDirect3DDevice2Impl_GetTransform,
847 IDirect3DDevice2Impl_MultiplyTransform,
849 MESA_IDirect3DDevice2Impl_DrawPrimitive,
850 MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive,
852 IDirect3DDevice2Impl_SetClipStatus,
853 IDirect3DDevice2Impl_GetClipStatus,
856 /*******************************************************************************
859 int d3d_OpenGL_dx3(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
862 TRACE(" Enumerating OpenGL D3D device (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
864 fill_opengl_caps(&d1, &d2);
866 return cb((void*)&IID_D3DDEVICE_OpenGL,"WINE Direct3D using OpenGL","direct3d",&d1,&d2,context);
869 int is_OpenGL_dx3(REFCLSID rguid, IDirectDrawSurfaceImpl* surface, IDirect3DDeviceImpl** device)
871 if (!memcmp(&IID_D3DDEVICE_OpenGL,rguid,sizeof(IID_D3DDEVICE_OpenGL))) {
872 mesa_d3dd_private *odev;
874 int attributeList[]={ GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None };
878 *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDeviceImpl));
879 (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
880 odev = (mesa_d3dd_private*)(*device)->private;
882 ICOM_VTBL(*device) = &OpenGL_vtable_dx3;
883 (*device)->d3d = NULL;
884 (*device)->surface = surface;
886 (*device)->viewport_list = NULL;
887 (*device)->current_viewport = NULL;
889 (*device)->set_context = (void*)set_context;
891 TRACE("OpenGL device created \n");
893 /* Create the OpenGL context */
895 odev->ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
896 odev->buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
897 surface->s.surface_desc.dwWidth * surface->s.surface_desc.dwHeight * 4);
899 /* First get the correct visual */
900 /* if (surface->s.backbuffer == NULL)
901 attributeList[3] = None; */
903 xvis = glXChooseVisual(gdi_display,
904 DefaultScreen(gdi_display),
907 ERR("No visual found !\n");
909 TRACE("Visual found\n");
910 /* Create the context */
911 odev->ctx = glXCreateContext(gdi_display,
915 TRACE("Context created\n");
917 #if 0 /* non working currently */
918 /* Now override the surface's Flip method (if in double buffering) */
919 surface->s.d3d_device = (void *) odev;
922 struct _surface_chain *chain = surface->s.chain;
923 for (i=0;i<chain->nrofsurfaces;i++)
924 if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
925 chain->surfaces[i]->s.d3d_device = (void *) odev;
929 odev->rs.src = GL_ONE;
930 odev->rs.dst = GL_ZERO;
931 odev->rs.mag = GL_NEAREST;
932 odev->rs.min = GL_NEAREST;
934 odev->world_mat = (LPD3DMATRIX) &id_mat;
935 odev->view_mat = (LPD3DMATRIX) &id_mat;
936 odev->proj_mat = (LPD3DMATRIX) &id_mat;
939 (*device)->set_context(*device);
940 glClearColor(0.0, 0.0, 0.0, 0.0);
941 glColor3f(1.0, 1.0, 1.0);
943 fill_device_capabilities((IDirectDrawImpl *) surface->ddraw_owner);
948 /* This is not the OpenGL UID */
952 static ULONG WINAPI MESA_IDirect3DDeviceImpl_Release(LPDIRECT3DDEVICE iface)
954 ICOM_THIS(IDirect3DDeviceImpl,iface);
955 FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
957 if (!--(This->ref)) {
960 OSMesaDestroyContext(odev->ctx);
963 glXDestroyContext(gdi_display, odev->ctx);
966 This->private = NULL;
967 HeapFree(GetProcessHeap(),0,This);
973 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EnumTextureFormats(
974 LPDIRECT3DDEVICE iface,LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc,
977 ICOM_THIS(IDirect3DDeviceImpl,iface);
978 TRACE("(%p)->(%p,%p): stub\n", This, lpd3dEnumTextureProc, lpArg);
980 return enum_texture_format_OpenGL(lpd3dEnumTextureProc, lpArg);
984 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_BeginScene(LPDIRECT3DDEVICE iface)
986 ICOM_THIS(IDirect3DDeviceImpl,iface);
987 /* OpenGL_IDirect3DDevice *odev = (OpenGL_IDirect3DDevice *) This; */
989 FIXME("(%p)->(): stub\n", This);
991 /* We get the pointer to the surface (should be done on flip) */
992 /* odev->zb->pbuf = This->surface->s.surface_desc.u2.lpSurface; */
998 /* This is for the moment copy-pasted from IDirect3DDevice2...
999 Will make a common function ... */
1000 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EndScene(LPDIRECT3DDEVICE iface)
1002 ICOM_THIS(IDirect3DDeviceImpl,iface);
1005 LPDIRECTDRAWSURFACE3 surf = (LPDIRECTDRAWSURFACE3) This->surface;
1006 DDSURFACEDESC sdesc;
1009 unsigned short *dest;
1012 FIXME("(%p)->(): stub\n", This);
1015 /* Here we copy back the OpenGL scene to the the DDraw surface */
1016 /* First, lock the surface */
1017 IDirectDrawSurface3_Lock(surf,NULL,&sdesc,DDLOCK_WRITEONLY,0);
1019 /* The copy the OpenGL buffer to this surface */
1021 /* NOTE : this is only for debugging purpose. I KNOW it is really unoptimal.
1022 I am currently working on a set of patches for Mesa to have OSMesa support
1023 16 bpp surfaces => we will able to render directly onto the surface, no
1024 need to do a bpp conversion */
1025 dest = (unsigned short *) sdesc.u2.lpSurface;
1026 src = ((unsigned char *) odev->buffer) + 4 * (sdesc.dwWidth * (sdesc.dwHeight - 1));
1027 for (y = 0; y < sdesc.dwHeight; y++) {
1028 unsigned char *lsrc = src;
1030 for (x = 0; x < sdesc.dwWidth ; x++) {
1031 unsigned char r = *lsrc++;
1032 unsigned char g = *lsrc++;
1033 unsigned char b = *lsrc++;
1036 *dest = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1041 src -= 4 * sdesc.dwWidth;
1044 /* Unlock the surface */
1045 IDirectDrawSurface3_Unlock(surf,sdesc.u2.lpSurface);
1047 /* No need to do anything here... */
1053 /*******************************************************************************
1054 * Direct3DDevice VTable
1056 ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3 =
1058 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1059 IDirect3DDeviceImpl_QueryInterface,
1060 IDirect3DDeviceImpl_AddRef,
1061 MESA_IDirect3DDeviceImpl_Release,
1062 IDirect3DDeviceImpl_Initialize,
1063 IDirect3DDeviceImpl_GetCaps,
1064 IDirect3DDeviceImpl_SwapTextureHandles,
1065 MESA_IDirect3DDeviceImpl_CreateExecuteBuffer,
1066 IDirect3DDeviceImpl_GetStats,
1067 IDirect3DDeviceImpl_Execute,
1068 IDirect3DDeviceImpl_AddViewport,
1069 IDirect3DDeviceImpl_DeleteViewport,
1070 IDirect3DDeviceImpl_NextViewport,
1071 IDirect3DDeviceImpl_Pick,
1072 IDirect3DDeviceImpl_GetPickRecords,
1073 MESA_IDirect3DDeviceImpl_EnumTextureFormats,
1074 IDirect3DDeviceImpl_CreateMatrix,
1075 IDirect3DDeviceImpl_SetMatrix,
1076 IDirect3DDeviceImpl_GetMatrix,
1077 IDirect3DDeviceImpl_DeleteMatrix,
1078 MESA_IDirect3DDeviceImpl_BeginScene,
1079 MESA_IDirect3DDeviceImpl_EndScene,
1080 IDirect3DDeviceImpl_GetDirect3D,