gdi32: Fix StretchDIBits return value when destination is clipped.
[wine] / dlls / gdi32 / opengl.c
1 /*
2  * OpenGL function forwarding to the display driver
3  *
4  * Copyright (c) 1999 Lionel Ulmer
5  * Copyright (c) 2005 Raphael Junqueira
6  * Copyright (c) 2006 Roderick Colenbrander
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winerror.h"
34 #include "winternl.h"
35 #include "winnt.h"
36 #include "gdi_private.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
40
41 static HDC default_hdc = 0;
42
43 typedef struct opengl_context
44 {
45     HDC hdc;
46 } *OPENGL_Context;
47
48 /* We route all wgl functions from opengl32.dll through gdi32.dll to
49  * the display driver. Various wgl calls have a hDC as one of their parameters.
50  * Using get_dc_ptr we get access to the functions exported by the driver.
51  * Some functions don't receive a hDC. This function creates a global hdc and
52  * if there's already a global hdc, it returns it.
53  */
54 static DC* OPENGL_GetDefaultDC(void)
55 {
56     if(!default_hdc)
57         default_hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
58
59     return get_dc_ptr(default_hdc);
60 }
61
62 /***********************************************************************
63  *              wglCopyContext (OPENGL32.@)
64  */
65 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
66 {
67     DC *dc;
68     BOOL ret = FALSE;
69     OPENGL_Context ctx = (OPENGL_Context)hglrcSrc;
70
71     TRACE("hglrcSrc: (%p), hglrcDst: (%p), mask: %#x\n", hglrcSrc, hglrcDst, mask);
72     /* If no context is set, this call doesn't have a purpose */
73     if(!hglrcSrc || !hglrcDst)
74         return FALSE;
75
76     /* Retrieve the HDC associated with the context to access the display driver */
77     dc = get_dc_ptr(ctx->hdc);
78     if (dc)
79     {
80         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglCopyContext );
81         ret = physdev->funcs->pwglCopyContext(hglrcSrc, hglrcDst, mask);
82         release_dc_ptr( dc );
83     }
84     return ret;
85 }
86
87 /***********************************************************************
88  *              wglCreateContext (OPENGL32.@)
89  */
90 HGLRC WINAPI wglCreateContext(HDC hdc)
91 {
92     HGLRC ret = 0;
93     DC * dc = get_dc_ptr( hdc );
94
95     TRACE("(%p)\n",hdc);
96
97     if (dc)
98     {
99         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglCreateContext );
100         update_dc( dc );
101         ret = physdev->funcs->pwglCreateContext( physdev );
102         release_dc_ptr( dc );
103     }
104     return ret;
105 }
106
107 /***********************************************************************
108  *      wglCreateContextAttribsARB
109  */
110 static HGLRC WINAPI wglCreateContextAttribsARB(HDC hdc, HGLRC hShareContext, const int *attributeList)
111 {
112     HGLRC ret = 0;
113     DC * dc = get_dc_ptr( hdc );
114
115     TRACE("(%p)\n",hdc);
116
117     if (dc)
118     {
119         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglCreateContextAttribsARB );
120         update_dc( dc );
121         ret = physdev->funcs->pwglCreateContextAttribsARB( physdev, hShareContext, attributeList );
122         release_dc_ptr( dc );
123     }
124     return ret;
125 }
126
127 /***********************************************************************
128  *              wglDeleteContext (OPENGL32.@)
129  */
130 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
131 {
132     DC *dc;
133     BOOL ret = FALSE;
134     OPENGL_Context ctx = (OPENGL_Context)hglrc;
135
136     TRACE("hglrc: (%p)\n", hglrc);
137     if(ctx == NULL)
138     {
139         SetLastError(ERROR_INVALID_HANDLE);
140         return FALSE;
141     }
142
143     /* Retrieve the HDC associated with the context to access the display driver */
144     dc = get_dc_ptr(ctx->hdc);
145     if (dc)
146     {
147         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglDeleteContext );
148         ret = physdev->funcs->pwglDeleteContext( hglrc );
149         release_dc_ptr( dc );
150     }
151     else SetLastError(ERROR_INVALID_HANDLE);
152     return ret;
153 }
154
155 /***********************************************************************
156  *              wglGetCurrentContext (OPENGL32.@)
157  */
158 HGLRC WINAPI wglGetCurrentContext(void)
159 {
160     HGLRC ret = NtCurrentTeb()->glContext;
161     TRACE(" returning %p\n", ret);
162     return ret;
163 }
164
165 /***********************************************************************
166  *              wglGetCurrentDC (OPENGL32.@)
167  */
168 HDC WINAPI wglGetCurrentDC(void)
169 {
170     OPENGL_Context ctx = (OPENGL_Context)wglGetCurrentContext();
171
172     TRACE(" found context: %p\n", ctx);
173     if(ctx == NULL)
174         return NULL;
175
176     /* Retrieve the current DC from the active context */
177     TRACE(" returning hdc: %p\n", ctx->hdc);
178     return ctx->hdc;
179 }
180
181 /***********************************************************************
182  *              wglMakeCurrent (OPENGL32.@)
183  */
184 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
185 {
186     BOOL ret = FALSE;
187     DC * dc = NULL;
188
189     /* When the context hglrc is NULL, the HDC is ignored and can be NULL.
190      * In that case use the global hDC to get access to the driver.  */
191     if(hglrc == NULL)
192     {
193         if( hdc == NULL && !wglGetCurrentContext() )
194         {
195             WARN( "Current context is NULL\n");
196             SetLastError( ERROR_INVALID_HANDLE );
197             return FALSE;
198         }
199         dc = OPENGL_GetDefaultDC();
200     }
201     else
202         dc = get_dc_ptr( hdc );
203
204     TRACE("hdc: (%p), hglrc: (%p)\n", hdc, hglrc);
205
206     if (dc)
207     {
208         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglMakeCurrent );
209         update_dc( dc );
210         ret = physdev->funcs->pwglMakeCurrent( physdev, hglrc );
211         release_dc_ptr( dc );
212     }
213     return ret;
214 }
215
216 /***********************************************************************
217  *              wglMakeContextCurrentARB
218  */
219 static BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
220 {
221     BOOL ret = FALSE;
222     PHYSDEV draw_physdev, read_physdev;
223     DC *DrawDC;
224     DC *ReadDC;
225
226     TRACE("hDrawDC: (%p), hReadDC: (%p) hglrc: (%p)\n", hDrawDC, hReadDC, hglrc);
227
228     /* Both hDrawDC and hReadDC need to be valid */
229     DrawDC = get_dc_ptr( hDrawDC );
230     if (!DrawDC) return FALSE;
231
232     ReadDC = get_dc_ptr( hReadDC );
233     if (!ReadDC) {
234         release_dc_ptr( DrawDC );
235         return FALSE;
236     }
237
238     update_dc( DrawDC );
239     update_dc( ReadDC );
240     draw_physdev = GET_DC_PHYSDEV( DrawDC, pwglMakeContextCurrentARB );
241     read_physdev = GET_DC_PHYSDEV( ReadDC, pwglMakeContextCurrentARB );
242     if (draw_physdev->funcs == read_physdev->funcs)
243         ret = draw_physdev->funcs->pwglMakeContextCurrentARB(draw_physdev, read_physdev, hglrc);
244     release_dc_ptr( DrawDC );
245     release_dc_ptr( ReadDC );
246     return ret;
247 }
248
249 /**************************************************************************************
250  *      WINE-specific wglSetPixelFormat which can set the iPixelFormat multiple times
251  *
252  */
253 static BOOL WINAPI wglSetPixelFormatWINE(HDC hdc, int iPixelFormat, const PIXELFORMATDESCRIPTOR *ppfd)
254 {
255     INT bRet = FALSE;
256     DC * dc = get_dc_ptr( hdc );
257
258     TRACE("(%p,%d,%p)\n", hdc, iPixelFormat, ppfd);
259
260     if (dc)
261     {
262         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglSetPixelFormatWINE );
263         update_dc( dc );
264         bRet = physdev->funcs->pwglSetPixelFormatWINE( physdev, iPixelFormat, ppfd );
265         release_dc_ptr( dc );
266     }
267     return bRet;
268 }
269
270 /***********************************************************************
271  *              wglShareLists (OPENGL32.@)
272  */
273 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2)
274 {
275     DC *dc;
276     BOOL ret = FALSE;
277     OPENGL_Context ctx = (OPENGL_Context)hglrc1;
278
279     TRACE("hglrc1: (%p); hglrc: (%p)\n", hglrc1, hglrc2);
280     if(ctx == NULL || hglrc2 == NULL)
281         return FALSE;
282
283     /* Retrieve the HDC associated with the context to access the display driver */
284     dc = get_dc_ptr(ctx->hdc);
285     if (dc)
286     {
287         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglShareLists );
288         ret = physdev->funcs->pwglShareLists( hglrc1, hglrc2 );
289         release_dc_ptr( dc );
290     }
291     return ret;
292 }
293
294 /***********************************************************************
295  *              wglUseFontBitmapsA (OPENGL32.@)
296  */
297 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
298 {
299     BOOL ret = FALSE;
300     DC * dc = get_dc_ptr( hdc );
301
302     TRACE("(%p, %d, %d, %d)\n", hdc, first, count, listBase);
303
304     if (dc)
305     {
306         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglUseFontBitmapsA );
307         ret = physdev->funcs->pwglUseFontBitmapsA( physdev, first, count, listBase );
308         release_dc_ptr( dc );
309     }
310     return ret;
311 }
312
313 /***********************************************************************
314  *              wglUseFontBitmapsW (OPENGL32.@)
315  */
316 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
317 {
318     BOOL ret = FALSE;
319     DC * dc = get_dc_ptr( hdc );
320
321     TRACE("(%p, %d, %d, %d)\n", hdc, first, count, listBase);
322
323     if (dc)
324     {
325         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglUseFontBitmapsW );
326         ret = physdev->funcs->pwglUseFontBitmapsW( physdev, first, count, listBase );
327         release_dc_ptr( dc );
328     }
329     return ret;
330 }
331
332 /***********************************************************************
333  *              Internal wglGetProcAddress for retrieving WGL extensions
334  */
335 PROC WINAPI wglGetProcAddress(LPCSTR func)
336 {
337     PROC ret = NULL;
338     DC *dc;
339
340     if(!func)
341         return NULL;
342
343     TRACE("func: '%s'\n", func);
344
345     /* Retrieve the global hDC to get access to the driver.  */
346     dc = OPENGL_GetDefaultDC();
347     if (dc)
348     {
349         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pwglGetProcAddress );
350         ret = physdev->funcs->pwglGetProcAddress(func);
351         release_dc_ptr( dc );
352     }
353
354     /* At the moment we implement one WGL extension which requires a HDC. When we
355      * are looking up this call and when the Extension is available (that is the case
356      * when a non-NULL value is returned by wglGetProcAddress), we return the address
357      * of a wrapper function which will handle the HDC->PhysDev conversion.
358      */
359     if(ret && strcmp(func, "wglCreateContextAttribsARB") == 0)
360         return (PROC)wglCreateContextAttribsARB;
361     else if(ret && strcmp(func, "wglMakeContextCurrentARB") == 0)
362         return (PROC)wglMakeContextCurrentARB;
363     else if(ret && strcmp(func, "wglSetPixelFormatWINE") == 0)
364         return (PROC)wglSetPixelFormatWINE;
365
366     return ret;
367 }