Restructured DirectDraw. Split into X11 and DGA driver, and multiple
files/dirs for easier maintenance. Cleaned up structs and include
files. Reindented the code. Started the same for Direct3D. Driver
inclusion now done by using configure/Makefile/ELF constructor tricks.
diff --git a/dlls/ddraw/d3ddevice/mesa.c b/dlls/ddraw/d3ddevice/mesa.c
new file mode 100644
index 0000000..0608a56
--- /dev/null
+++ b/dlls/ddraw/d3ddevice/mesa.c
@@ -0,0 +1,1036 @@
+/* Direct3D Device
+ (c) 1998 Lionel ULMER
+
+ This files contains the MESA implementation of all the D3D devices that
+ Wine supports. */
+
+#include <string.h>
+#include "config.h"
+#include "windef.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "heap.h"
+#include "ddraw.h"
+#include "d3d.h"
+#include "debugtools.h"
+
+#include "mesa_private.h"
+
+DEFAULT_DEBUG_CHANNEL(ddraw)
+
+ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable;
+ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3;
+
+/* Define this variable if you have an unpatched Mesa 3.0 (patches are available
+ on Mesa's home page) or version 3.1b.
+
+ Version 3.1b2 should correct this bug */
+#undef HAVE_BUGGY_MESAGL
+
+#define D3DDPRIVATE(x) mesa_d3dd_private *odev=((mesa_d3dd_private*)x->private)
+#define DDPRIVATE(x) x11_dd_private *ddpriv=((x11_dd_private*)(x)->private)
+
+/*******************************************************************************
+ * OpenGL static functions
+ */
+static void set_context(IDirect3DDevice2Impl* This) {
+ D3DDPRIVATE(This);
+ DDPRIVATE(This->surface->s.ddraw);
+
+#ifdef USE_OSMESA
+ OSMesaMakeCurrent(d3ddpriv->ctx, odev->buffer, GL_UNSIGNED_BYTE,
+ This->surface->s.surface_desc.dwWidth,
+ This->surface->s.surface_desc.dwHeight);
+#else
+ if (glXMakeCurrent(display,ddpriv->drawable, odev->ctx) == False) {
+ ERR("Error in setting current context (context %p drawable %ld)!\n",
+ odev->ctx, ddpriv->drawable);
+}
+#endif
+}
+
+static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
+{
+ pc->dwSize = sizeof(*pc);
+ pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
+ D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
+ pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
+ D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST;
+ pc->dwZCmpCaps = 0xFFFFFFFF; /* All Z test can be done */
+ pc->dwSrcBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
+ pc->dwDestBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
+ pc->dwAlphaCmpCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
+ pc->dwShadeCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
+ pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
+ D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
+ pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
+ D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
+ pc->dwTextureBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
+ pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP;
+ pc->dwStippleWidth = 32;
+ pc->dwStippleHeight = 32;
+}
+
+static void fill_opengl_caps(D3DDEVICEDESC *d1, D3DDEVICEDESC *d2)
+{
+ /* GLint maxlight; */
+
+ d1->dwSize = sizeof(*d1);
+ d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
+ | D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
+ d1->dcmColorModel = D3DCOLOR_RGB;
+ d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
+ D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
+ D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
+ d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
+ d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
+ d1->bClipping = TRUE;
+ d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
+ d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
+ d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
+ d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
+ fill_opengl_primcaps(&(d1->dpcLineCaps));
+ fill_opengl_primcaps(&(d1->dpcTriCaps));
+ d1->dwDeviceRenderBitDepth = DDBD_16;
+ d1->dwDeviceZBufferBitDepth = DDBD_16;
+ d1->dwMaxBufferSize = 0;
+ d1->dwMaxVertexCount = 65536;
+ d1->dwMinTextureWidth = 1;
+ d1->dwMinTextureHeight = 1;
+ d1->dwMaxTextureWidth = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
+ d1->dwMaxTextureHeight = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
+ d1->dwMinStippleWidth = 1;
+ d1->dwMinStippleHeight = 1;
+ d1->dwMaxStippleWidth = 32;
+ d1->dwMaxStippleHeight = 32;
+
+ d2->dwSize = sizeof(*d2);
+ d2->dwFlags = 0;
+}
+
+int d3d_OpenGL(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
+ D3DDEVICEDESC d1,d2;
+ TRACE(" Enumerating OpenGL D3D device.\n");
+ fill_opengl_caps(&d1, &d2);
+ return cb((void*)&IID_D3DDEVICE2_OpenGL,"WINE Direct3D using OpenGL","direct3d",&d1,&d2,context);
+}
+
+int
+is_OpenGL(
+ REFCLSID rguid, IDirectDrawSurfaceImpl* surface,
+ IDirect3DDevice2Impl** device, IDirect3D2Impl* d3d
+) {
+ mesa_d3dd_private *odev = NULL;
+
+ if (/* Default device */
+ (rguid == NULL) ||
+ /* HAL Device */
+ (!memcmp(&IID_IDirect3DHALDevice,rguid,sizeof(IID_IDirect3DHALDevice))) ||
+ /* OpenGL Device */
+ (!memcmp(&IID_D3DDEVICE2_OpenGL,rguid,sizeof(IID_D3DDEVICE2_OpenGL)))) {
+
+ const float id_mat[16] = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+ };
+#ifndef USE_OSMESA
+ int attributeList[]={ GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None };
+ XVisualInfo *xvis;
+#endif
+
+ *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDevice2Impl));
+ (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
+ odev = (mesa_d3dd_private*)(*device)->private;
+ (*device)->ref = 1;
+ ICOM_VTBL(*device) = &OpenGL_vtable;
+ (*device)->d3d = d3d;
+ (*device)->surface = surface;
+ (*device)->viewport_list = NULL;
+ (*device)->current_viewport = NULL;
+ (*device)->set_context = set_context;
+
+ TRACE("Creating OpenGL device for surface %p\n", surface);
+ /* Create the OpenGL context */
+#ifdef USE_OSMESA
+ odev->ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
+ odev->buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+ surface->s.surface_desc.dwWidth * surface->s.surface_desc.dwHeight * 4);
+#else
+ /* First get the correct visual */
+ /* if (surface->s.backbuffer == NULL)
+ attributeList[3] = None; */
+ ENTER_GL();
+ xvis = glXChooseVisual(display,
+ DefaultScreen(display),
+ attributeList);
+ if (xvis == NULL)
+ ERR("No visual found !\n");
+ else
+ TRACE("Visual found\n");
+ /* Create the context */
+ odev->ctx = glXCreateContext(display,
+ xvis,
+ NULL,
+ GL_TRUE);
+ if (odev->ctx == NULL)
+ ERR("Error in context creation !\n");
+ else
+ TRACE("Context created (%p)\n", odev->ctx);
+
+#if 0 /* not functional currently */
+ /* Now override the surface's Flip method (if in double buffering) */
+ surface->s.d3d_device = (void *) odev;
+
+ {
+ int i;
+ struct _surface_chain *chain = surface->s.chain;
+ for (i=0;i<chain->nrofsurfaces;i++)
+ if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
+ chain->surfaces[i]->s.d3d_device = (void *) odev;
+ }
+#endif
+
+#endif
+ odev->rs.src = GL_ONE;
+ odev->rs.dst = GL_ZERO;
+ odev->rs.mag = GL_NEAREST;
+ odev->rs.min = GL_NEAREST;
+ odev->vt = 0;
+
+ memcpy(odev->world_mat, id_mat, 16 * sizeof(float));
+ memcpy(odev->view_mat , id_mat, 16 * sizeof(float));
+ memcpy(odev->proj_mat , id_mat, 16 * sizeof(float));
+
+ /* Initialisation */
+ TRACE("Setting current context\n");
+ (*device)->set_context(*device);
+ TRACE("Current context set\n");
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glColor3f(1.0, 1.0, 1.0);
+ LEAVE_GL();
+ TRACE("OpenGL device created \n");
+ return 1;
+ }
+ FIXME("bad IID %s\n",debugstr_guid(rguid));
+ /* This is not the OpenGL UID */
+ return 0;
+}
+
+/*******************************************************************************
+ * MESA IDirect3DDevice2
+ */
+static ULONG WINAPI MESA_IDirect3DDevice2Impl_Release(LPDIRECT3DDEVICE2 iface)
+{
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ D3DDPRIVATE(This);
+ FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
+
+ if (!--(This->ref)) {
+#ifdef USE_OSMESA
+ OSMesaDestroyContext(odev->ctx);
+#else
+ ENTER_GL();
+ glXDestroyContext(display, odev->ctx);
+ LEAVE_GL();
+#endif
+ This->private = NULL;
+ HeapFree(GetProcessHeap(),0,This);
+ return 0;
+ }
+ return This->ref;
+}
+
+/*** IDirect3DDevice2 methods ***/
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_GetCaps(
+ LPDIRECT3DDEVICE2 iface, LPD3DDEVICEDESC lpdescsoft,
+ LPD3DDEVICEDESC lpdeschard
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ FIXME("(%p)->(%p,%p): stub\n", This, lpdescsoft, lpdeschard);
+ fill_opengl_caps(lpdescsoft, lpdeschard);
+ return DD_OK;
+}
+
+static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb,
+ LPVOID context) {
+ DDSURFACEDESC sdesc;
+ LPDDPIXELFORMAT pformat;
+
+ /* Do the texture enumeration */
+ sdesc.dwSize = sizeof(DDSURFACEDESC);
+ sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
+ sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+ pformat = &(sdesc.ddpfPixelFormat);
+ pformat->dwSize = sizeof(DDPIXELFORMAT);
+ pformat->dwFourCC = 0;
+
+ TRACE("Enumerating GL_RGBA unpacked (32)\n");
+ pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+ pformat->u.dwRGBBitCount = 32;
+ pformat->u1.dwRBitMask = 0xFF000000;
+ pformat->u2.dwGBitMask = 0x00FF0000;
+ pformat->u3.dwBBitMask = 0x0000FF00;
+ pformat->u4.dwRGBAlphaBitMask = 0x000000FF;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+
+ TRACE("Enumerating GL_RGB unpacked (24)\n");
+ pformat->dwFlags = DDPF_RGB;
+ pformat->u.dwRGBBitCount = 24;
+ pformat->u1.dwRBitMask = 0x00FF0000;
+ pformat->u2.dwGBitMask = 0x0000FF00;
+ pformat->u3.dwBBitMask = 0x000000FF;
+ pformat->u4.dwRGBAlphaBitMask = 0x00000000;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+
+#ifndef HAVE_BUGGY_MESAGL
+ /* The packed texture format are buggy in Mesa. The bug was reported and corrected,
+ so that future version will work great. */
+ TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
+ pformat->dwFlags = DDPF_RGB;
+ pformat->u.dwRGBBitCount = 16;
+ pformat->u1.dwRBitMask = 0x0000F800;
+ pformat->u2.dwGBitMask = 0x000007E0;
+ pformat->u3.dwBBitMask = 0x0000001F;
+ pformat->u4.dwRGBAlphaBitMask = 0x00000000;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+
+ TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
+ pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+ pformat->u.dwRGBBitCount = 16;
+ pformat->u1.dwRBitMask = 0x0000F800;
+ pformat->u2.dwGBitMask = 0x000007C0;
+ pformat->u3.dwBBitMask = 0x0000003E;
+ pformat->u4.dwRGBAlphaBitMask = 0x00000001;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+
+ TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
+ pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+ pformat->u.dwRGBBitCount = 16;
+ pformat->u1.dwRBitMask = 0x0000F000;
+ pformat->u2.dwGBitMask = 0x00000F00;
+ pformat->u3.dwBBitMask = 0x000000F0;
+ pformat->u4.dwRGBAlphaBitMask = 0x0000000F;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+
+ TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
+ pformat->dwFlags = DDPF_RGB;
+ pformat->u.dwRGBBitCount = 8;
+ pformat->u1.dwRBitMask = 0x0000F800;
+ pformat->u2.dwGBitMask = 0x000007C0;
+ pformat->u3.dwBBitMask = 0x0000003E;
+ pformat->u4.dwRGBAlphaBitMask = 0x00000001;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+#endif
+
+#if defined(HAVE_GL_COLOR_TABLE) && defined(HAVE_GL_PALETTED_TEXTURE)
+ TRACE("Enumerating Paletted (8)\n");
+ pformat->dwFlags = DDPF_PALETTEINDEXED8;
+ pformat->u.dwRGBBitCount = 8;
+ pformat->u1.dwRBitMask = 0x00000000;
+ pformat->u2.dwGBitMask = 0x00000000;
+ pformat->u3.dwBBitMask = 0x00000000;
+ pformat->u4.dwRGBAlphaBitMask = 0x00000000;
+ if (cb(&sdesc, context) == 0)
+ return DD_OK;
+#endif
+
+ TRACE("End of enumeration\n");
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_EnumTextureFormats(
+ LPDIRECT3DDEVICE2 iface, LPD3DENUMTEXTUREFORMATSCALLBACK cb, LPVOID context
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ FIXME("(%p)->(%p,%p): stub\n", This, cb, context);
+
+ return enum_texture_format_OpenGL(cb, context);
+}
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_BeginScene(
+ LPDIRECT3DDEVICE2 iface
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+
+ FIXME("(%p)->(): stub\n", This);
+
+ /* Here, we should get the DDraw surface and 'copy it' to the
+ OpenGL surface.... */
+
+ return DD_OK;
+}
+
+HRESULT WINAPI MESA_IDirect3DDevice2Impl_EndScene(LPDIRECT3DDEVICE2 iface) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+#ifdef USE_OSMESA
+ D3DPRIVATE(This);
+
+ LPDIRECTDRAWSURFACE3 surf = (LPDIRECTDRAWSURFACE3) This->surface;
+ DDSURFACEDESC sdesc;
+ int x,y;
+ unsigned char *src;
+ unsigned short *dest;
+#endif
+
+ FIXME("(%p)->(): stub\n", This);
+
+#ifdef USE_OSMESA
+ /* Here we copy back the OpenGL scene to the the DDraw surface */
+ /* First, lock the surface */
+ IDirectDrawSurface3_Lock(surf,NULL,&sdesc,DDLOCK_WRITEONLY,0);
+
+ /* The copy the OpenGL buffer to this surface */
+
+ /* NOTE : this is only for debugging purpose. I KNOW it is really unoptimal.
+ I am currently working on a set of patches for Mesa to have OSMesa support
+ 16 bpp surfaces => we will able to render directly onto the surface, no
+ need to do a bpp conversion */
+ dest = (unsigned short *) sdesc.y.lpSurface;
+ src = ((unsigned char *) odev->buffer) + 4 * (sdesc.dwWidth * (sdesc.dwHeight - 1));
+ for (y = 0; y < sdesc.dwHeight; y++) {
+ unsigned char *lsrc = src;
+
+ for (x = 0; x < sdesc.dwWidth ; x++) {
+ unsigned char r = *lsrc++;
+ unsigned char g = *lsrc++;
+ unsigned char b = *lsrc++;
+ lsrc++; /* Alpha */
+ *dest = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+
+ dest++;
+ }
+
+ src -= 4 * sdesc.dwWidth;
+ }
+
+ /* Unlock the surface */
+ IDirectDrawSurface3_Unlock(surf,sdesc.y.lpSurface);
+#else
+ /* No need to do anything here... */
+#endif
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetRenderState(
+ LPDIRECT3DDEVICE2 iface, D3DRENDERSTATETYPE dwRenderStateType,
+ DWORD dwRenderState
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ D3DDPRIVATE(This);
+
+ TRACE("(%p)->(%d,%ld)\n", This, dwRenderStateType, dwRenderState);
+
+ /* Call the render state functions */
+ set_render_state(dwRenderStateType, dwRenderState, &(odev->rs));
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetLightState(
+ LPDIRECT3DDEVICE2 iface, D3DLIGHTSTATETYPE dwLightStateType,
+ DWORD dwLightState
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ FIXME("(%p)->(%d,%08lx): stub\n", This, dwLightStateType, dwLightState);
+
+ switch (dwLightStateType) {
+ case D3DLIGHTSTATE_MATERIAL: { /* 1 */
+ IDirect3DMaterial2Impl* mat = (IDirect3DMaterial2Impl*) dwLightState;
+
+ if (mat != NULL) {
+ ENTER_GL();
+ mat->activate(mat);
+ LEAVE_GL();
+ } else {
+ TRACE("Zoups !!!\n");
+ }
+ } break;
+
+ case D3DLIGHTSTATE_AMBIENT: { /* 2 */
+ float light[4];
+
+ light[0] = ((dwLightState >> 16) & 0xFF) / 255.0;
+ light[1] = ((dwLightState >> 8) & 0xFF) / 255.0;
+ light[2] = ((dwLightState >> 0) & 0xFF) / 255.0;
+ light[3] = 1.0;
+ ENTER_GL();
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
+ LEAVE_GL();
+ } break;
+
+#define UNSUP(x) case D3DLIGHTSTATE_##x: FIXME("unsupported D3DLIGHTSTATE_" #x "!\n");break;
+ UNSUP(COLORMODEL);
+ UNSUP(FOGMODE);
+ UNSUP(FOGSTART);
+ UNSUP(FOGEND);
+ UNSUP(FOGDENSITY);
+#undef UNSUP
+ default:
+ TRACE("Unexpected Light State Type\n");
+ return DDERR_INVALIDPARAMS;
+ }
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetTransform(
+ LPDIRECT3DDEVICE2 iface, D3DTRANSFORMSTATETYPE d3dts,
+ LPD3DMATRIX lpmatrix
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ D3DDPRIVATE(This);
+
+ FIXME("(%p)->(%d,%p): stub\n", This, d3dts, lpmatrix);
+
+ ENTER_GL();
+
+ /* Using a trial and failure approach, I found that the order of
+ Direct3D transformations that works best is :
+
+ ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
+
+ As OpenGL uses only two matrices, I combined PROJECTION and VIEW into
+ OpenGL's GL_PROJECTION matrix and the WORLD into GL_MODELVIEW.
+
+ If anyone has a good explanation of the three different matrices in
+ the SDK online documentation, feel free to point it to me. For example,
+ which matrices transform lights ? In OpenGL only the PROJECTION matrix
+ transform the lights, not the MODELVIEW. Using the matrix names, I
+ supposed that PROJECTION and VIEW (all 'camera' related names) do
+ transform lights, but WORLD do not. It may be wrong though... */
+
+ /* After reading through both OpenGL and Direct3D documentations, I
+ thought that D3D matrices were written in 'line major mode' transposed
+ from OpenGL's 'column major mode'. But I found out that a simple memcpy
+ works fine to transfer one matrix format to the other (it did not work
+ when transposing)....
+
+ So :
+ 1) are the documentations wrong
+ 2) does the matrix work even if they are not read correctly
+ 3) is Mesa's implementation of OpenGL not compliant regarding Matrix
+ loading using glLoadMatrix ?
+
+ Anyway, I always use 'conv_mat' to transfer the matrices from one format
+ to the other so that if I ever find out that I need to transpose them, I
+ will able to do it quickly, only by changing the macro conv_mat. */
+
+ switch (d3dts) {
+ case D3DTRANSFORMSTATE_WORLD: {
+ conv_mat(lpmatrix, odev->world_mat);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf((float *) &(odev->world_mat));
+ } break;
+
+ case D3DTRANSFORMSTATE_VIEW: {
+ conv_mat(lpmatrix, odev->view_mat);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf((float *) &(odev->proj_mat));
+ glMultMatrixf((float *) &(odev->view_mat));
+ } break;
+
+ case D3DTRANSFORMSTATE_PROJECTION: {
+ conv_mat(lpmatrix, odev->proj_mat);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf((float *) &(odev->proj_mat));
+ glMultMatrixf((float *) &(odev->view_mat));
+ } break;
+
+ default:
+ break;
+ }
+ LEAVE_GL();
+ return DD_OK;
+}
+
+#define DRAW_PRIMITIVE(MAXVERT,INDEX) \
+ /* Puts GL in the correct lighting mode */ \
+ if (odev->vt != d3dv) { \
+ if (odev->vt == D3DVT_TLVERTEX) { \
+ /* Need to put the correct transformation again */ \
+ glMatrixMode(GL_MODELVIEW); \
+ glLoadMatrixf((float *) &(odev->world_mat)); \
+ glMatrixMode(GL_PROJECTION); \
+ glLoadMatrixf((float *) &(odev->proj_mat)); \
+ glMultMatrixf((float *) &(odev->view_mat)); \
+ } \
+ \
+ switch (d3dv) { \
+ case D3DVT_VERTEX: \
+ TRACE("Standard Vertex\n"); \
+ glEnable(GL_LIGHTING); \
+ break; \
+ \
+ case D3DVT_LVERTEX: \
+ TRACE("Lighted Vertex\n"); \
+ glDisable(GL_LIGHTING); \
+ break; \
+ \
+ case D3DVT_TLVERTEX: { \
+ GLdouble height, width, minZ, maxZ; \
+ \
+ TRACE("Transformed - Lighted Vertex\n"); \
+ /* First, disable lighting */ \
+ glDisable(GL_LIGHTING); \
+ \
+ /* Then do not put any transformation matrixes */ \
+ glMatrixMode(GL_MODELVIEW); \
+ glLoadIdentity(); \
+ glMatrixMode(GL_PROJECTION); \
+ glLoadIdentity(); \
+ \
+ if (This->current_viewport == NULL) { \
+ ERR("No current viewport !\n"); \
+ /* Using standard values */ \
+ height = 640.0; \
+ width = 480.0; \
+ minZ = -10.0; \
+ maxZ = 10.0; \
+ } else { \
+ if (This->current_viewport->use_vp2) { \
+ height = (GLdouble) This->current_viewport->viewport.vp2.dwHeight;\
+ width = (GLdouble) This->current_viewport->viewport.vp2.dwWidth;\
+ minZ = (GLdouble) This->current_viewport->viewport.vp2.dvMinZ;\
+ maxZ = (GLdouble) This->current_viewport->viewport.vp2.dvMaxZ;\
+ } else { \
+ height = (GLdouble) This->current_viewport->viewport.vp1.dwHeight;\
+ width = (GLdouble) This->current_viewport->viewport.vp1.dwWidth;\
+ minZ = (GLdouble) This->current_viewport->viewport.vp1.dvMinZ;\
+ maxZ = (GLdouble) This->current_viewport->viewport.vp1.dvMaxZ;\
+ } \
+ } \
+ \
+ glOrtho(0.0, width, height, 0.0, -minZ, -maxZ); \
+ } break; \
+ \
+ default: \
+ ERR("Unhandled vertex type\n"); \
+ break; \
+ } \
+ \
+ odev->vt = d3dv; \
+ } \
+ \
+ switch (d3dp) { \
+ case D3DPT_POINTLIST: \
+ TRACE("Start POINTS\n"); \
+ glBegin(GL_POINTS); \
+ break; \
+ \
+ case D3DPT_LINELIST: \
+ TRACE("Start LINES\n"); \
+ glBegin(GL_LINES); \
+ break; \
+ \
+ case D3DPT_LINESTRIP: \
+ TRACE("Start LINE_STRIP\n"); \
+ glBegin(GL_LINE_STRIP); \
+ break; \
+ \
+ case D3DPT_TRIANGLELIST: \
+ TRACE("Start TRIANGLES\n"); \
+ glBegin(GL_TRIANGLES); \
+ break; \
+ \
+ case D3DPT_TRIANGLESTRIP: \
+ TRACE("Start TRIANGLE_STRIP\n"); \
+ glBegin(GL_TRIANGLE_STRIP); \
+ break; \
+ \
+ case D3DPT_TRIANGLEFAN: \
+ TRACE("Start TRIANGLE_FAN\n"); \
+ glBegin(GL_TRIANGLE_FAN); \
+ break; \
+ \
+ default: \
+ TRACE("Unhandled primitive\n"); \
+ break; \
+ } \
+ \
+ /* Draw the primitives */ \
+ for (vx_index = 0; vx_index < MAXVERT; vx_index++) { \
+ switch (d3dv) { \
+ case D3DVT_VERTEX: { \
+ D3DVERTEX *vx = ((D3DVERTEX *) lpvertex) + INDEX; \
+ \
+ glNormal3f(vx->nx.nx, vx->ny.ny, vx->nz.nz); \
+ glVertex3f(vx->x.x, vx->y.y, vx->z.z); \
+ TRACE(" V: %f %f %f\n", vx->x.x, vx->y.y, vx->z.z); \
+ } break; \
+ \
+ case D3DVT_LVERTEX: { \
+ D3DLVERTEX *vx = ((D3DLVERTEX *) lpvertex) + INDEX; \
+ DWORD col = vx->c.color; \
+ \
+ glColor3f(((col >> 16) & 0xFF) / 255.0, \
+ ((col >> 8) & 0xFF) / 255.0, \
+ ((col >> 0) & 0xFF) / 255.0); \
+ glVertex3f(vx->x.x, vx->y.y, vx->z.z); \
+ TRACE(" LV: %f %f %f (%02lx %02lx %02lx)\n", \
+ vx->x.x, vx->y.y, vx->z.z, \
+ ((col >> 16) & 0xFF), ((col >> 8) & 0xFF), ((col >> 0) & 0xFF));\
+ } break; \
+ \
+ case D3DVT_TLVERTEX: { \
+ D3DTLVERTEX *vx = ((D3DTLVERTEX *) lpvertex) + INDEX; \
+ DWORD col = vx->c.color; \
+ \
+ glColor3f(((col >> 16) & 0xFF) / 255.0, \
+ ((col >> 8) & 0xFF) / 255.0, \
+ ((col >> 0) & 0xFF) / 255.0); \
+ glTexCoord2f(vx->u.tu, vx->v.tv); \
+ if (vx->r.rhw < 0.01) \
+ glVertex3f(vx->x.sx, \
+ vx->y.sy, \
+ vx->z.sz); \
+ else \
+ glVertex4f(vx->x.sx / vx->r.rhw, \
+ vx->y.sy / vx->r.rhw, \
+ vx->z.sz / vx->r.rhw, \
+ 1.0 / vx->r.rhw); \
+ TRACE(" TLV: %f %f %f (%02lx %02lx %02lx) (%f %f) (%f)\n", \
+ vx->x.sx, vx->y.sy, vx->z.sz, \
+ ((col >> 16) & 0xFF), ((col >> 8) & 0xFF), ((col >> 0) & 0xFF),\
+ vx->u.tu, vx->v.tv, vx->r.rhw); \
+ } break; \
+ \
+ default: \
+ FIXME("Unhandled vertex type\n"); \
+ break; \
+ } \
+ } \
+ \
+ glEnd(); \
+ TRACE("End\n");
+
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawPrimitive(
+ LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
+ LPVOID lpvertex, DWORD vertcount, DWORD dwFlags
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ D3DDPRIVATE(This);
+ int vx_index;
+
+ TRACE("(%p)->(%d,%d,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, dwFlags);
+
+ ENTER_GL();
+ DRAW_PRIMITIVE(vertcount, vx_index);
+ LEAVE_GL();
+
+ return D3D_OK;
+}
+
+static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive(
+ LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
+ LPVOID lpvertex, DWORD vertcount, LPWORD lpindexes, DWORD indexcount,
+ DWORD dwFlags
+) {
+ ICOM_THIS(IDirect3DDevice2Impl,iface);
+ D3DDPRIVATE(This);
+ int vx_index;
+
+ TRACE("(%p)->(%d,%d,%p,%ld,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, lpindexes, indexcount, dwFlags);
+
+ ENTER_GL();
+ DRAW_PRIMITIVE(indexcount, lpindexes[vx_index]);
+ LEAVE_GL();
+
+ return D3D_OK;
+}
+
+/*******************************************************************************
+ * OpenGL-specific IDirect3DDevice2
+ */
+
+/*******************************************************************************
+ * OpenGL-specific VTable
+ */
+
+ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ IDirect3DDevice2Impl_QueryInterface,
+ IDirect3DDevice2Impl_AddRef,
+ MESA_IDirect3DDevice2Impl_Release,
+ /*** IDirect3DDevice2 methods ***/
+ MESA_IDirect3DDevice2Impl_GetCaps,
+ IDirect3DDevice2Impl_SwapTextureHandles,
+ IDirect3DDevice2Impl_GetStats,
+ IDirect3DDevice2Impl_AddViewport,
+ IDirect3DDevice2Impl_DeleteViewport,
+ IDirect3DDevice2Impl_NextViewport,
+ MESA_IDirect3DDevice2Impl_EnumTextureFormats,
+ MESA_IDirect3DDevice2Impl_BeginScene,
+ MESA_IDirect3DDevice2Impl_EndScene,
+ IDirect3DDevice2Impl_GetDirect3D,
+
+ /*** DrawPrimitive API ***/
+ IDirect3DDevice2Impl_SetCurrentViewport,
+ IDirect3DDevice2Impl_GetCurrentViewport,
+
+ IDirect3DDevice2Impl_SetRenderTarget,
+ IDirect3DDevice2Impl_GetRenderTarget,
+
+ IDirect3DDevice2Impl_Begin,
+ IDirect3DDevice2Impl_BeginIndexed,
+ IDirect3DDevice2Impl_Vertex,
+ IDirect3DDevice2Impl_Index,
+ IDirect3DDevice2Impl_End,
+
+ IDirect3DDevice2Impl_GetRenderState,
+ MESA_IDirect3DDevice2Impl_SetRenderState,
+ IDirect3DDevice2Impl_GetLightState,
+ MESA_IDirect3DDevice2Impl_SetLightState,
+ MESA_IDirect3DDevice2Impl_SetTransform,
+ IDirect3DDevice2Impl_GetTransform,
+ IDirect3DDevice2Impl_MultiplyTransform,
+
+ MESA_IDirect3DDevice2Impl_DrawPrimitive,
+ MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive,
+
+ IDirect3DDevice2Impl_SetClipStatus,
+ IDirect3DDevice2Impl_GetClipStatus,
+};
+
+/*******************************************************************************
+ * Direct3DDevice
+ */
+int d3d_OpenGL_dx3(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
+ D3DDEVICEDESC d1,d2;
+
+ TRACE(" Enumerating OpenGL D3D device.\n");
+
+ fill_opengl_caps(&d1, &d2);
+
+ return cb((void*)&IID_D3DDEVICE_OpenGL,"WINE Direct3D using OpenGL","direct3d",&d1,&d2,context);
+}
+
+float id_mat[16] = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+};
+
+int is_OpenGL_dx3(REFCLSID rguid, IDirectDrawSurfaceImpl* surface, IDirect3DDeviceImpl** device)
+{
+ if (!memcmp(&IID_D3DDEVICE_OpenGL,rguid,sizeof(IID_D3DDEVICE_OpenGL))) {
+ mesa_d3dd_private *odev;
+#ifndef USE_OSMESA
+ int attributeList[]={ GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None };
+ XVisualInfo *xvis;
+#endif
+
+ *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDeviceImpl));
+ (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
+ odev = (mesa_d3dd_private*)(*device)->private;
+ (*device)->ref = 1;
+ ICOM_VTBL(*device) = &OpenGL_vtable_dx3;
+ (*device)->d3d = NULL;
+ (*device)->surface = surface;
+
+ (*device)->viewport_list = NULL;
+ (*device)->current_viewport = NULL;
+
+ (*device)->set_context = (void*)set_context;
+
+ TRACE("OpenGL device created \n");
+
+ /* Create the OpenGL context */
+#ifdef USE_OSMESA
+ odev->ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
+ odev->buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+ surface->s.surface_desc.dwWidth * surface->s.surface_desc.dwHeight * 4);
+#else
+ /* First get the correct visual */
+ /* if (surface->s.backbuffer == NULL)
+ attributeList[3] = None; */
+ ENTER_GL();
+ xvis = glXChooseVisual(display,
+ DefaultScreen(display),
+ attributeList);
+ if (xvis == NULL)
+ ERR("No visual found !\n");
+ else
+ TRACE("Visual found\n");
+ /* Create the context */
+ odev->ctx = glXCreateContext(display,
+ xvis,
+ NULL,
+ GL_TRUE);
+ TRACE("Context created\n");
+
+#if 0 /* non working currently */
+ /* Now override the surface's Flip method (if in double buffering) */
+ surface->s.d3d_device = (void *) odev;
+ {
+ int i;
+ struct _surface_chain *chain = surface->s.chain;
+ for (i=0;i<chain->nrofsurfaces;i++)
+ if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
+ chain->surfaces[i]->s.d3d_device = (void *) odev;
+ }
+#endif
+#endif
+ odev->rs.src = GL_ONE;
+ odev->rs.dst = GL_ZERO;
+ odev->rs.mag = GL_NEAREST;
+ odev->rs.min = GL_NEAREST;
+
+ odev->world_mat = (LPD3DMATRIX) &id_mat;
+ odev->view_mat = (LPD3DMATRIX) &id_mat;
+ odev->proj_mat = (LPD3DMATRIX) &id_mat;
+
+ /* Initialisation */
+ (*device)->set_context(*device);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glColor3f(1.0, 1.0, 1.0);
+
+ return 1;
+ }
+
+ /* This is not the OpenGL UID */
+ return DD_OK;
+}
+
+static ULONG WINAPI MESA_IDirect3DDeviceImpl_Release(LPDIRECT3DDEVICE iface)
+{
+ ICOM_THIS(IDirect3DDeviceImpl,iface);
+ FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
+
+ if (!--(This->ref)) {
+ D3DDPRIVATE(This);
+#ifdef USE_OSMESA
+ OSMesaDestroyContext(odev->ctx);
+#else
+ ENTER_GL();
+ glXDestroyContext(display, odev->ctx);
+ LEAVE_GL();
+#endif
+ This->private = NULL;
+ HeapFree(GetProcessHeap(),0,This);
+ return 0;
+ }
+ return This->ref;
+}
+
+static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EnumTextureFormats(
+ LPDIRECT3DDEVICE iface,LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc,
+ LPVOID lpArg)
+{
+ ICOM_THIS(IDirect3DDeviceImpl,iface);
+ TRACE("(%p)->(%p,%p): stub\n", This, lpd3dEnumTextureProc, lpArg);
+
+ return enum_texture_format_OpenGL(lpd3dEnumTextureProc, lpArg);
+}
+
+
+static HRESULT WINAPI MESA_IDirect3DDeviceImpl_BeginScene(LPDIRECT3DDEVICE iface)
+{
+ ICOM_THIS(IDirect3DDeviceImpl,iface);
+ /* OpenGL_IDirect3DDevice *odev = (OpenGL_IDirect3DDevice *) This; */
+
+ FIXME("(%p)->(): stub\n", This);
+
+ /* We get the pointer to the surface (should be done on flip) */
+ /* odev->zb->pbuf = This->surface->s.surface_desc.y.lpSurface; */
+
+ return DD_OK;
+}
+
+
+/* This is for the moment copy-pasted from IDirect3DDevice2...
+ Will make a common function ... */
+static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EndScene(LPDIRECT3DDEVICE iface)
+{
+ ICOM_THIS(IDirect3DDeviceImpl,iface);
+#ifdef USE_OSMESA
+ D3DDPRIVATE(This);
+ LPDIRECTDRAWSURFACE3 surf = (LPDIRECTDRAWSURFACE3) This->surface;
+ DDSURFACEDESC sdesc;
+ int x,y;
+ unsigned char *src;
+ unsigned short *dest;
+#endif
+
+ FIXME("(%p)->(): stub\n", This);
+
+#ifdef USE_OSMESA
+ /* Here we copy back the OpenGL scene to the the DDraw surface */
+ /* First, lock the surface */
+ IDirectDrawSurface3_Lock(surf,NULL,&sdesc,DDLOCK_WRITEONLY,0);
+
+ /* The copy the OpenGL buffer to this surface */
+
+ /* NOTE : this is only for debugging purpose. I KNOW it is really unoptimal.
+ I am currently working on a set of patches for Mesa to have OSMesa support
+ 16 bpp surfaces => we will able to render directly onto the surface, no
+ need to do a bpp conversion */
+ dest = (unsigned short *) sdesc.y.lpSurface;
+ src = ((unsigned char *) odev->buffer) + 4 * (sdesc.dwWidth * (sdesc.dwHeight - 1));
+ for (y = 0; y < sdesc.dwHeight; y++) {
+ unsigned char *lsrc = src;
+
+ for (x = 0; x < sdesc.dwWidth ; x++) {
+ unsigned char r = *lsrc++;
+ unsigned char g = *lsrc++;
+ unsigned char b = *lsrc++;
+ lsrc++; /* Alpha */
+
+ *dest = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+
+ dest++;
+ }
+
+ src -= 4 * sdesc.dwWidth;
+ }
+
+ /* Unlock the surface */
+ IDirectDrawSurface3_Unlock(surf,sdesc.y.lpSurface);
+#else
+ /* No need to do anything here... */
+#endif
+
+ return DD_OK;
+}
+
+/*******************************************************************************
+ * Direct3DDevice VTable
+ */
+ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3 =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ IDirect3DDeviceImpl_QueryInterface,
+ IDirect3DDeviceImpl_AddRef,
+ MESA_IDirect3DDeviceImpl_Release,
+ IDirect3DDeviceImpl_Initialize,
+ IDirect3DDeviceImpl_GetCaps,
+ IDirect3DDeviceImpl_SwapTextureHandles,
+ IDirect3DDeviceImpl_CreateExecuteBuffer,
+ IDirect3DDeviceImpl_GetStats,
+ IDirect3DDeviceImpl_Execute,
+ IDirect3DDeviceImpl_AddViewport,
+ IDirect3DDeviceImpl_DeleteViewport,
+ IDirect3DDeviceImpl_NextViewport,
+ IDirect3DDeviceImpl_Pick,
+ IDirect3DDeviceImpl_GetPickRecords,
+ MESA_IDirect3DDeviceImpl_EnumTextureFormats,
+ IDirect3DDeviceImpl_CreateMatrix,
+ IDirect3DDeviceImpl_SetMatrix,
+ IDirect3DDeviceImpl_GetMatrix,
+ IDirect3DDeviceImpl_DeleteMatrix,
+ MESA_IDirect3DDeviceImpl_BeginScene,
+ MESA_IDirect3DDeviceImpl_EndScene,
+ IDirect3DDeviceImpl_GetDirect3D,
+};