diff --git a/dlls/ddraw/d3d_private.h b/dlls/ddraw/d3d_private.h
index b1f320ca6861b51b4c98607d6ee1711fa1821350..73f82cada7635bcd6c393be0561ad03bfc0f7e32 100644
--- a/dlls/ddraw/d3d_private.h
+++ b/dlls/ddraw/d3d_private.h
@@ -178,6 +178,12 @@ struct IDirect3DExecuteBufferImpl
                     IDirect3DViewportImpl* vp);
 };
 
+/* Internal structure to store the state of the clipping planes */
+typedef struct d3d7clippingplane 
+{
+    D3DVALUE plane[4];
+} d3d7clippingplane;
+
 /*****************************************************************************
  * IDirect3DDevice implementation structure
  */
@@ -218,6 +224,10 @@ struct IDirect3DDeviceImpl
     DWORD active_lights, set_lights;
     D3DLIGHT7 light_parameters[MAX_LIGHTS];
 
+    /* clipping planes */
+    DWORD max_clipping_planes;
+    d3d7clippingplane *clipping_planes;
+    
     void (*set_context)(IDirect3DDeviceImpl*);
     HRESULT (*clear)(IDirect3DDeviceImpl *This,
 		     DWORD dwCount,
diff --git a/dlls/ddraw/d3ddevice/main.c b/dlls/ddraw/d3ddevice/main.c
index 2e8a6f97dc459945f5b43edceaa65194c414e7f9..05452bbbbe00b49ba84c58c3ad3cea7565fae490 100644
--- a/dlls/ddraw/d3ddevice/main.c
+++ b/dlls/ddraw/d3ddevice/main.c
@@ -875,14 +875,20 @@ Main_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface,
     return DD_OK;
 }
 
-HRESULT WINAPI
-Main_IDirect3DDeviceImpl_7_GetClipPlane(LPDIRECT3DDEVICE7 iface,
-                                        DWORD dwIndex,
-                                        D3DVALUE* pPlaneEquation)
+HRESULT  WINAPI  
+Main_IDirect3DDeviceImpl_7_GetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, D3DVALUE* pPlaneEquation)
 {
-    ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
-    FIXME("(%p/%p)->(%08lx,%p): stub!\n", This, iface, dwIndex, pPlaneEquation);
-    return DD_OK;
+    ICOM_THIS(IDirect3DDeviceImpl,iface);
+
+    TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
+
+    if (dwIndex>=This->max_clipping_planes) {
+	return DDERR_INVALIDPARAMS;
+    }
+
+    memcpy( pPlaneEquation, This->clipping_planes[dwIndex].plane, sizeof(D3DVALUE[4]));
+
+    return D3D_OK;
 }
 
 HRESULT WINAPI
diff --git a/dlls/ddraw/d3ddevice/mesa.c b/dlls/ddraw/d3ddevice/mesa.c
index ea72ff33438b8db3457bc0eed2fdff68acbc3b28..c2f175e41fbf1236e9497fb1f2d98dd1be5f6e3e 100644
--- a/dlls/ddraw/d3ddevice/mesa.c
+++ b/dlls/ddraw/d3ddevice/mesa.c
@@ -328,6 +328,7 @@ GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
 	ENTER_GL();
 	glXDestroyContext(glThis->display, glThis->gl_context);
 	LEAVE_GL();
+	HeapFree(GetProcessHeap(), 0, This->clipping_planes);
 
 	HeapFree(GetProcessHeap(), 0, This);
 	return 0;
@@ -1572,6 +1573,32 @@ GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
     return DD_OK;
 }
 
+HRESULT  WINAPI  
+GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation) 
+{
+    ICOM_THIS(IDirect3DDeviceImpl,iface);
+    GLdouble plane[4];
+
+    TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
+
+    if (dwIndex>=This->max_clipping_planes) {
+	return DDERR_INVALIDPARAMS;
+    }
+
+    TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
+
+    memcpy( This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
+    plane[0] = pPlaneEquation[0];
+    plane[1] = pPlaneEquation[1];
+    plane[2] = pPlaneEquation[2];
+    plane[3] = pPlaneEquation[3];
+
+    /* XXX: is here also code needed to handle the transformation of the world? */
+    glClipPlane( GL_CLIP_PLANE0+dwIndex, (const GLdouble*)(&plane) );
+
+    return D3D_OK;
+}
+
 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice7.fun))
 #else
@@ -1627,7 +1654,7 @@ ICOM_VTABLE(IDirect3DDevice7) VTABLE_IDirect3DDevice7 =
     XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
     XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
     XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
-    XCAST(SetClipPlane) Main_IDirect3DDeviceImpl_7_SetClipPlane,
+    XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
     XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
     XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
 };
@@ -2036,6 +2063,7 @@ d3ddevice_create(IDirect3DDeviceImpl **obj, IDirect3DImpl *d3d, IDirectDrawSurfa
     XVisualInfo template;
     GLenum buffer = GL_FRONT;
     int light;
+    GLint max_clipping_planes = 0;
     
     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
     if (object == NULL) return DDERR_OUTOFMEMORY;
@@ -2136,6 +2164,16 @@ d3ddevice_create(IDirect3DDeviceImpl **obj, IDirect3DImpl *d3d, IDirectDrawSurfa
     memcpy(object->view_mat , id_mat, 16 * sizeof(float));
     memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
 
+    /* allocate the clipping planes */
+    glGetIntegerv(GL_MAX_CLIP_PLANES,&max_clipping_planes);
+    if (max_clipping_planes>32) {
+	object->max_clipping_planes=32;
+    } else {
+	object->max_clipping_planes = max_clipping_planes;
+    }
+    TRACE(" capable of %d clipping planes\n", (int)object->max_clipping_planes );
+    object->clipping_planes = (d3d7clippingplane*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
+
     /* Initialisation */
     TRACE(" setting current context\n");
     LEAVE_GL();
diff --git a/dlls/ddraw/mesa.c b/dlls/ddraw/mesa.c
index a0a016f87620f700c5ffdc797423691b104cae7b..9e370d752ac6706cea3ddeb6f93690a1ca542106 100644
--- a/dlls/ddraw/mesa.c
+++ b/dlls/ddraw/mesa.c
@@ -455,8 +455,24 @@ void set_render_state(IDirect3DDeviceGLImpl* This,
 	        break;
 
 	    case D3DRENDERSTATE_CLIPPING:    /* 136 */
-	        /* Nothing to do here... Even if what we receive is already clipped by the application,
-		   we cannot tell OpenGL to not re-clip it. */
+	    case D3DRENDERSTATE_CLIPPLANEENABLE: /*152*/
+		{
+		    GLint i;
+		    DWORD mask, runner;
+		    
+		    if (dwRenderStateType==D3DRENDERSTATE_CLIPPING) {
+			mask = ((dwRenderState)?(This->parent.state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE-1]):(0x0000));
+		    } else {
+			mask = dwRenderState;
+		    }
+		    for (i = 0, runner = 1; i < This->parent.max_clipping_planes; i++, runner = (runner<<1)) {
+			if (mask & runner) {
+			    glEnable(GL_CLIP_PLANE0 + i);
+			} else {
+			    glDisable(GL_CLIP_PLANE0 + i);
+			}
+		    }
+		}
 	        break;
 
 	    case D3DRENDERSTATE_LIGHTING:    /* 137 */