move mesa32 over to new dir
[reactos.git] / reactos / lib / opengl32 / wgl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/opengl32/wgl.c
5 * PURPOSE: OpenGL32 lib, rosglXXX functions
6 * PROGRAMMER: Anich Gregor (blight)
7 * UPDATE HISTORY:
8 * Feb 2, 2004: Created
9 */
10
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32_NO_STATUS
13 #include <windows.h>
14
15 #define NTOS_MODE_USER
16 #include <ddraw.h>
17 #include <ddrawi.h>
18 #include <winddi.h>
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "teb.h"
25
26 #define OPENGL32_GL_FUNC_PROTOTYPES
27 #include "opengl32.h"
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif /* __cplusplus */
32
33 #if !defined(UNIMPLEMENTED)
34 # define UNIMPLEMENTED DBGPRINT( "UNIMPLEMENTED" )
35 #endif
36
37
38 typedef struct _OPENGL_INFO
39 {
40 DWORD Version; /*!< Driver interface version */
41 DWORD DriverVersion; /*!< Driver version */
42 WCHAR DriverName[256]; /*!< Driver name */
43 } OPENGL_INFO, *POPENGL_INFO;
44
45
46 /*! \brief Append OpenGL Rendering Context (GLRC) to list
47 *
48 * \param glrc [IN] Pointer to GLRC to append to list
49 */
50 static
51 void
52 ROSGL_AppendContext( GLRC *glrc )
53 {
54 /* synchronize */
55 if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
56 WAIT_FAILED)
57 {
58 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
59 return; /* FIXME: do we have to expect such an error and handle it? */
60 }
61
62 if (OPENGL32_processdata.glrc_list == NULL)
63 OPENGL32_processdata.glrc_list = glrc;
64 else
65 {
66 GLRC *p = OPENGL32_processdata.glrc_list;
67 while (p->next != NULL)
68 p = p->next;
69 p->next = glrc;
70 }
71
72 /* release mutex */
73 if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
74 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
75 }
76
77
78 /*! \brief Remove OpenGL Rendering Context (GLRC) from list
79 *
80 * \param glrc [IN] Pointer to GLRC to remove from list
81 */
82 static
83 void
84 ROSGL_RemoveContext( GLRC *glrc )
85 {
86 /* synchronize */
87 if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
88 WAIT_FAILED)
89 {
90 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
91 return; /* FIXME: do we have to expect such an error and handle it? */
92 }
93
94 if (glrc == OPENGL32_processdata.glrc_list)
95 OPENGL32_processdata.glrc_list = glrc->next;
96 else
97 {
98 GLRC *p = OPENGL32_processdata.glrc_list;
99 while (p != NULL)
100 {
101 if (p->next == glrc)
102 {
103 p->next = glrc->next;
104 break;
105 }
106 p = p->next;
107 }
108 if (p == NULL)
109 DBGPRINT( "Error: GLRC 0x%08x not found in list!", glrc );
110 }
111
112 /* release mutex */
113 if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
114 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
115 }
116
117
118 /*! \brief Create a new GL Context (GLRC) and append it to the list
119 *
120 * \return Pointer to new GLRC on success
121 * \retval NULL Returned on failure (i.e. Out of memory)
122 */
123 static
124 GLRC *
125 ROSGL_NewContext()
126 {
127 GLRC *glrc;
128
129 /* allocate GLRC */
130 glrc = (GLRC*)HeapAlloc( GetProcessHeap(),
131 HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, sizeof (GLRC) );
132
133 /* append to list */
134 ROSGL_AppendContext( glrc );
135
136 return glrc;
137 }
138
139
140 /*! \brief Delete a GL Context (GLRC) and remove it from the list
141 *
142 * \param glrc [IN] Pointer to GLRC to delete
143 *
144 * \retval TRUE Success
145 * \retval FALSE Failure
146 */
147 static
148 BOOL
149 ROSGL_DeleteContext( GLRC *glrc )
150 {
151 /* unload icd */
152 if (glrc->icd != NULL)
153 OPENGL32_UnloadICD( glrc->icd );
154
155 /* remove from list */
156 ROSGL_RemoveContext( glrc );
157
158 /* free memory */
159 HeapFree( GetProcessHeap(), 0, glrc );
160
161 return TRUE;
162 }
163
164
165 /*! \brief Check wether a GLRC is in the list
166 *
167 * \param glrc [IN] Pointer to GLRC to look for in the list
168 *
169 * \retval TRUE GLRC was found
170 * \retval FALSE GLRC was not found
171 */
172 static
173 BOOL
174 ROSGL_ContainsContext( GLRC *glrc )
175 {
176 GLRC *p;
177 BOOL found = FALSE;
178
179 /* synchronize */
180 if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
181 WAIT_FAILED)
182 {
183 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
184 return FALSE; /* FIXME: do we have to expect such an error and handle it? */
185 }
186
187 p = OPENGL32_processdata.glrc_list;
188 while (p != NULL)
189 {
190 if (p == glrc)
191 {
192 found = TRUE;
193 break;
194 }
195 p = p->next;
196 }
197
198 /* release mutex */
199 if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
200 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
201
202 return found;
203 }
204
205
206 /*! \brief Get GL private DC data.
207 *
208 * This function adds an empty GLDCDATA to the list if there is no data for the
209 * given DC yet.
210 *
211 * \param hdc [IN] Handle to a Device Context for which to get the data
212 *
213 * \return Pointer to GLDCDATA on success
214 * \retval NULL on failure
215 */
216 static
217 GLDCDATA *
218 ROSGL_GetPrivateDCData( HDC hdc )
219 {
220 GLDCDATA *data;
221
222 /* check hdc */
223 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
224 {
225 DBGPRINT( "Error: hdc is not a DC handle!" );
226 SetLastError( ERROR_INVALID_HANDLE );
227 return FALSE;
228 }
229
230 /* synchronize */
231 if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
232 WAIT_FAILED)
233 {
234 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
235 return NULL; /* FIXME: do we have to expect such an error and handle it? */
236 }
237
238 /* look for data in list */
239 data = OPENGL32_processdata.dcdata_list;
240 while (data != NULL)
241 {
242 if (data->hdc == hdc) /* found */
243 break;
244 data = data->next;
245 }
246
247 /* allocate new data if not found in list */
248 if (data == NULL)
249 {
250 data = HeapAlloc( GetProcessHeap(),
251 HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS,
252 sizeof (GLDCDATA) );
253 if (data == NULL)
254 {
255 DBGPRINT( "Error: HeapAlloc() failed (%d)", GetLastError() );
256 }
257 else
258 {
259 data->hdc = hdc;
260
261 /* append data to list */
262 if (OPENGL32_processdata.dcdata_list == NULL)
263 OPENGL32_processdata.dcdata_list = data;
264 else
265 {
266 GLDCDATA *p = OPENGL32_processdata.dcdata_list;
267 while (p->next != NULL)
268 p = p->next;
269 p->next = data;
270 }
271 }
272 }
273
274 /* release mutex */
275 if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
276 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
277
278 return data;
279 }
280
281
282 /*! \brief Get ICD from HDC.
283 *
284 * This function asks the display driver which OpenGL ICD to load for the given
285 * HDC, loads it and returns a pointer to a GLDRIVERDATA struct on success.
286 *
287 * \param hdc [IN] Handle for DC for which to load/get the ICD
288 *
289 * \return Pointer to GLDRIVERDATA
290 * \retval NULL Failure.
291 */
292 static
293 GLDRIVERDATA *
294 ROSGL_ICDForHDC( HDC hdc )
295 {
296 GLDCDATA *dcdata;
297
298 dcdata = ROSGL_GetPrivateDCData( hdc );
299 if (dcdata == NULL)
300 return NULL;
301
302 if (dcdata->icd == NULL)
303 {
304 LPCWSTR driverName;
305 OPENGL_INFO info;
306
307 driverName = _wgetenv( L"OPENGL32_DRIVER" );
308 if (driverName == NULL)
309 {
310 DWORD dwInput;
311 LONG ret;
312
313 /* get driver name */
314 dwInput = OPENGL_GETINFO;
315 ret = ExtEscape( hdc, QUERYESCSUPPORT, sizeof (dwInput), (LPCSTR)&dwInput, 0, NULL );
316 if (ret > 0)
317 {
318 dwInput = 0;
319 ret = ExtEscape( hdc, OPENGL_GETINFO, sizeof (dwInput),
320 (LPCSTR)&dwInput, sizeof (OPENGL_INFO),
321 (LPSTR)&info );
322 }
323 if (ret <= 0)
324 {
325 HKEY hKey;
326 DWORD type, size;
327
328 if (ret < 0)
329 {
330 DBGPRINT( "Warning: ExtEscape to get the drivername failed! (%d)", GetLastError() );
331 if (MessageBox( WindowFromDC( hdc ), L"Couldn't get installable client driver name!\nUsing default driver.",
332 L"OPENGL32.dll: Warning", MB_OKCANCEL | MB_ICONWARNING ) == IDCANCEL)
333 {
334 return NULL;
335 }
336 }
337
338 /* open registry key */
339 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, OPENGL_DRIVERS_SUBKEY, 0, KEY_READ, &hKey );
340 if (ret != ERROR_SUCCESS)
341 {
342 DBGPRINT( "Error: Couldn't open registry key '%ws'", OPENGL_DRIVERS_SUBKEY );
343 SetLastError( ret );
344 return NULL;
345 }
346
347 /* query value */
348 size = sizeof (info.DriverName);
349 ret = RegQueryValueExW( hKey, L"DefaultDriver", 0, &type, (LPBYTE)info.DriverName, &size );
350 RegCloseKey( hKey );
351 if (ret != ERROR_SUCCESS || type != REG_SZ)
352 {
353 DBGPRINT( "Error: Couldn't query DefaultDriver value or not a string" );
354 SetLastError( ret );
355 return NULL;
356 }
357 }
358 }
359 else
360 {
361 wcsncpy( info.DriverName, driverName, sizeof (info.DriverName) / sizeof (info.DriverName[0]) );
362 }
363 /* load driver (or get a reference) */
364 dcdata->icd = OPENGL32_LoadICD( info.DriverName );
365 if (dcdata->icd == NULL)
366 {
367 WCHAR Buffer[256];
368 snwprintf(Buffer, sizeof(Buffer)/sizeof(WCHAR),
369 L"Couldn't load driver \"%s\".", driverName);
370 MessageBox(WindowFromDC( hdc ), Buffer,
371 L"OPENGL32.dll: Warning",
372 MB_OK | MB_ICONWARNING);
373 }
374 }
375
376 return dcdata->icd;
377 }
378
379
380 /*! \brief SetContextCallBack passed to DrvSetContext.
381 *
382 * This function gets called by the OpenGL driver whenever the current GL
383 * context (dispatch table) is to be changed.
384 *
385 * \param table [IN] Function pointer table (first DWORD is number of functions)
386 *
387 * \return unkown (maybe void? ERROR_SUCCESS at the moment)
388 */
389 DWORD
390 CALLBACK
391 ROSGL_SetContextCallBack( const ICDTable *table )
392 {
393 TEB *teb;
394 PROC *tebTable, *tebDispatchTable;
395 INT size;
396
397 teb = NtCurrentTeb();
398 tebTable = (PROC *)teb->glTable;
399 tebDispatchTable = (PROC *)teb->glDispatchTable;
400
401 DBGTRACE( "Called!" );
402
403 if (table != NULL)
404 {
405 DBGPRINT( "Function count: %d\n", table->num_funcs );
406
407 /* save table */
408 size = sizeof (PROC) * table->num_funcs;
409 memcpy( tebTable, table->dispatch_table, size );
410 memset( tebTable + table->num_funcs, 0,
411 sizeof (table->dispatch_table) - size );
412 }
413 else
414 {
415 DBGPRINT( "Unsetting current context" );
416 memset( tebTable, 0, sizeof (table->dispatch_table) );
417 }
418
419 /* put in empty functions as long as we dont have a fallback */
420 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
421 if (tebTable[icdidx] == NULL) \
422 { \
423 if (table != NULL) \
424 DBGPRINT( "Warning: GL proc '%s' is NULL", #func ); \
425 tebTable[icdidx] = (PROC)glEmptyFunc##stack; \
426 }
427 GLFUNCS_MACRO
428 #undef X
429
430 /* fill teb->glDispatchTable for fast calls */
431 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
432 if (tebidx >= 0) \
433 tebDispatchTable[tebidx] = tebTable[icdidx];
434 GLFUNCS_MACRO
435 #undef X
436
437 DBGPRINT( "Done." );
438
439 return ERROR_SUCCESS;
440 }
441
442
443 /*! \brief Attempts to find the best matching pixel format for HDC
444 *
445 * This function is comparing each available format with the preferred one
446 * and returns the one which is closest to it.
447 * If PFD_DOUBLEBUFFER, PFD_STEREO or one of PFD_DRAW_TO_WINDOW,
448 * PFD_DRAW_TO_BITMAP, PFD_SUPPORT_GDI and PDF_SUPPORT_OPENGL is given then
449 * only formats which also support those will be enumerated (unless
450 * PFD_DOUBLEBUFFER_DONTCARE or PFD_STEREO_DONTCARE is also set)
451 *
452 * \param hdc [IN] Handle to DC for which to get a pixel format index
453 * \param pfd [IN] PFD describing what kind of format you want
454 *
455 * \return Pixel format index
456 * \retval 0 Failed to find a suitable format
457 */
458 #define BUFFERDEPTH_SCORE(want, have) \
459 ((want == 0) ? (0) : ((want < have) ? (1) : ((want > have) ? (3) : (0))))
460 int
461 APIENTRY
462 rosglChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
463 {
464 GLDRIVERDATA *icd;
465 PIXELFORMATDESCRIPTOR icdPfd;
466 int i;
467 int best = 0;
468 int score, bestScore = 0x7fff; /* used to choose a pfd if no exact match */
469 int icdNumFormats;
470 const DWORD compareFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP |
471 PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL;
472
473 DBGTRACE( "Called!" );
474
475 /* load ICD */
476 icd = ROSGL_ICDForHDC( hdc );
477 if (icd == NULL)
478 return 0;
479
480 /* check input */
481 if (pfd->nSize != sizeof (PIXELFORMATDESCRIPTOR) || pfd->nVersion != 1)
482 {
483 SetLastError( ERROR_INVALID_PARAMETER );
484 return 0;
485 }
486
487 /* get number of formats */
488 icdNumFormats = icd->DrvDescribePixelFormat( hdc, 1,
489 sizeof (PIXELFORMATDESCRIPTOR), &icdPfd );
490 if (icdNumFormats == 0)
491 {
492 DBGPRINT( "Error: DrvDescribePixelFormat failed (%d)", GetLastError() );
493 return 0;
494 }
495 DBGPRINT( "Info: Enumerating %d pixelformats", icdNumFormats );
496
497 /* try to find best format */
498 for (i = 0; i < icdNumFormats; i++)
499 {
500 if (icd->DrvDescribePixelFormat( hdc, i + 1,
501 sizeof (PIXELFORMATDESCRIPTOR), &icdPfd ) == 0)
502 {
503 DBGPRINT( "Warning: DrvDescribePixelFormat failed (%d)",
504 GetLastError() );
505 break;
506 }
507
508 if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) != 0) /* we do not support such kind of drivers */
509 {
510 continue;
511 }
512
513 /* compare flags */
514 if ((pfd->dwFlags & compareFlags) != (icdPfd.dwFlags & compareFlags))
515 continue;
516 if (!(pfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) &&
517 ((pfd->dwFlags & PFD_DOUBLEBUFFER) != (icdPfd.dwFlags & PFD_DOUBLEBUFFER)))
518 continue;
519 if (!(pfd->dwFlags & PFD_STEREO_DONTCARE) &&
520 ((pfd->dwFlags & PFD_STEREO) != (icdPfd.dwFlags & PFD_STEREO)))
521 continue;
522
523 /* check other attribs */
524 score = 0; /* higher is worse */
525 if (pfd->iPixelType != icdPfd.iPixelType)
526 score += 5; /* this is really bad i think */
527 if (pfd->iLayerType != icdPfd.iLayerType)
528 score += 15; /* this is very very bad ;) */
529
530 score += BUFFERDEPTH_SCORE(pfd->cAlphaBits, icdPfd.cAlphaBits);
531 score += BUFFERDEPTH_SCORE(pfd->cAccumBits, icdPfd.cAccumBits);
532 score += BUFFERDEPTH_SCORE(pfd->cDepthBits, icdPfd.cDepthBits);
533 score += BUFFERDEPTH_SCORE(pfd->cStencilBits, icdPfd.cStencilBits);
534 score += BUFFERDEPTH_SCORE(pfd->cAuxBuffers, icdPfd.cAuxBuffers);
535
536 /* check score */
537 if (score < bestScore)
538 {
539 bestScore = score;
540 best = i + 1;
541 if (bestScore == 0)
542 break;
543 }
544 }
545
546 if (best == 0)
547 SetLastError( 0 ); /* FIXME: set appropriate error */
548
549 DBGPRINT( "Info: Suggesting pixelformat %d", best );
550 return best;
551 }
552
553
554 /*! \brief Copy data specified by mask from one GLRC to another.
555 *
556 * \param src [IN] Source GLRC
557 * \param src [OUT] Destination GLRC
558 * \param mask [IN] Bitfield like given to glPushAttrib()
559 *
560 * \retval TRUE Success
561 * \retval FALSE Failure
562 */
563 BOOL
564 APIENTRY
565 rosglCopyContext( HGLRC hsrc, HGLRC hdst, UINT mask )
566 {
567 GLRC *src = (GLRC *)hsrc;
568 GLRC *dst = (GLRC *)hdst;
569
570 /* check glrcs */
571 if (!ROSGL_ContainsContext( src ))
572 {
573 DBGPRINT( "Error: src GLRC not found!" );
574 SetLastError( ERROR_INVALID_HANDLE );
575 return FALSE;
576 }
577 if (!ROSGL_ContainsContext( dst ))
578 {
579 DBGPRINT( "Error: dst GLRC not found!" );
580 SetLastError( ERROR_INVALID_HANDLE );
581 return FALSE;
582 }
583
584 /* I think this is only possible within one ICD */
585 if (src->icd != src->icd)
586 {
587 DBGPRINT( "Error: src and dst GLRC use different ICDs!" );
588 SetLastError( ERROR_INVALID_HANDLE );
589 return FALSE;
590 }
591
592 /* copy data (call ICD) */
593 return src->icd->DrvCopyContext( src->hglrc, dst->hglrc, mask );
594 }
595
596
597 /*! \brief Create a new GL Rendering Context.
598 *
599 * This function can create over- or underlay surfaces.
600 *
601 * \param hdc [IN] Handle for DC for which to create context
602 * \param layer [IN] Layer number to bind (draw?) to
603 *
604 * \return Handle for the created GLRC
605 * \retval NULL Failure
606 */
607 HGLRC
608 APIENTRY
609 rosglCreateLayerContext( HDC hdc, int layer )
610 {
611 GLDRIVERDATA *icd = NULL;
612 GLRC *glrc;
613 HGLRC drvHglrc = NULL;
614
615 DBGTRACE( "Called!" );
616
617 /* if (GetObjectType( hdc ) != OBJ_DC)
618 {
619 DBGPRINT( "Error: hdc is not a DC handle!" );
620 return NULL;
621 }
622 */
623 /* create new GLRC */
624 glrc = ROSGL_NewContext();
625 if (glrc == NULL)
626 return NULL;
627
628 /* load ICD */
629 icd = ROSGL_ICDForHDC( hdc );
630 if (icd == NULL)
631 {
632 ROSGL_DeleteContext( glrc );
633 DBGPRINT( "Couldn't get ICD by HDC :-(" );
634 /* FIXME: fallback? */
635 return NULL;
636 }
637
638 /* create context */
639 if (icd->DrvCreateLayerContext != NULL)
640 drvHglrc = icd->DrvCreateLayerContext( hdc, layer );
641 if (drvHglrc == NULL)
642 {
643 if (layer == 0 && icd->DrvCreateContext != NULL)
644 drvHglrc = icd->DrvCreateContext( hdc );
645 else
646 DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
647 }
648
649 if (drvHglrc == NULL)
650 {
651 /* FIXME: fallback to mesa? */
652 DBGPRINT( "Error: DrvCreate[Layer]Context failed! (%d)", GetLastError() );
653 ROSGL_DeleteContext( glrc );
654 return NULL;
655 }
656
657 /* we have our GLRC in glrc and the ICD's GLRC in drvHglrc */
658 glrc->hglrc = drvHglrc;
659 glrc->icd = icd;
660
661 return (HGLRC)glrc;
662 }
663
664
665 /*! \brief Create a new GL Rendering Context.
666 *
667 * \param hdc [IN] Handle for DC for which to create context
668 *
669 * \return Handle for the created GLRC
670 * \retval NULL Failure
671 */
672 HGLRC
673 APIENTRY
674 rosglCreateContext( HDC hdc )
675 {
676 return rosglCreateLayerContext( hdc, 0 );
677 }
678
679
680 /*! \brief Delete an OpenGL context
681 *
682 * \param hglrc [IN] Handle to GLRC to delete; must not be a threads current RC!
683 *
684 * \retval TRUE Success
685 * \retval FALSE Failure (i.e. GLRC is current for a thread)
686 */
687 BOOL
688 APIENTRY
689 rosglDeleteContext( HGLRC hglrc )
690 {
691 GLRC *glrc = (GLRC *)hglrc;
692
693 /* check if we know about this context */
694 if (!ROSGL_ContainsContext( glrc ))
695 {
696 DBGPRINT( "Error: hglrc not found!" );
697 SetLastError( ERROR_INVALID_HANDLE );
698 return FALSE;
699 }
700
701 /* make sure GLRC is not current for some thread */
702 if (glrc->is_current)
703 {
704 DBGPRINT( "Error: GLRC is current for DC 0x%08x", glrc->hdc );
705 SetLastError( ERROR_INVALID_FUNCTION );
706 return FALSE;
707 }
708
709 /* release ICD's context */
710 if (glrc->hglrc != NULL)
711 {
712 if (!glrc->icd->DrvDeleteContext( glrc->hglrc ))
713 {
714 DBGPRINT( "Warning: DrvDeleteContext() failed (%d)", GetLastError() );
715 return FALSE;
716 }
717 }
718
719 /* free resources */
720 return ROSGL_DeleteContext( glrc );
721 }
722
723
724 BOOL
725 APIENTRY
726 rosglDescribeLayerPlane( HDC hdc, int iPixelFormat, int iLayerPlane,
727 UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd )
728 {
729 UNIMPLEMENTED;
730 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
731 return FALSE;
732 }
733
734
735 /*! \brief Gets information about a pixelformat.
736 *
737 * \param hdc [IN] Handle to DC
738 * \param iFormat [IN] Pixelformat index
739 * \param nBytes [IN] sizeof (pfd) - at most nBytes are copied into pfd
740 * \param pfd [OUT] Pointer to a PIXELFORMATDESCRIPTOR
741 *
742 * \return Maximum pixelformat index/number of formats
743 * \retval 0 Failure
744 */
745 int
746 APIENTRY
747 rosglDescribePixelFormat( HDC hdc, int iFormat, UINT nBytes,
748 LPPIXELFORMATDESCRIPTOR pfd )
749 {
750 int ret = 0;
751 GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
752
753 if (icd != NULL)
754 {
755 ret = icd->DrvDescribePixelFormat( hdc, iFormat, nBytes, pfd );
756 if (ret == 0)
757 DBGPRINT( "Error: DrvDescribePixelFormat(format=%d) failed (%d)", iFormat, GetLastError() );
758 }
759 else
760 {
761 SetLastError( ERROR_INVALID_FUNCTION );
762 }
763
764 return ret;
765 }
766
767
768 /*! \brief Return the thread's current GLRC
769 *
770 * \return Handle for thread's current GLRC
771 * \retval NULL No current GLRC set
772 */
773 HGLRC
774 APIENTRY
775 rosglGetCurrentContext()
776 {
777 return (HGLRC)(OPENGL32_threaddata->glrc);
778 }
779
780
781 /*! \brief Return the thread's current DC
782 *
783 * \return Handle for thread's current DC
784 * \retval NULL No current DC/GLRC set
785 */
786 HDC
787 APIENTRY
788 rosglGetCurrentDC()
789 {
790 /* FIXME: is it correct to return NULL when there is no current GLRC or
791 is there another way to find out the wanted HDC? */
792 if (OPENGL32_threaddata->glrc == NULL)
793 return NULL;
794 return (HDC)(OPENGL32_threaddata->glrc->hdc);
795 }
796
797
798 int
799 APIENTRY
800 rosglGetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
801 int cEntries, COLORREF *pcr )
802 {
803 UNIMPLEMENTED;
804 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
805 return 0;
806 }
807
808
809 /*! \brief Returns the current pixelformat.
810 *
811 * \param hdc [IN] Handle to DC to get the pixelformat from
812 *
813 * \return Pixelformat index
814 * \retval 0 Failure
815 */
816 int
817 WINAPI
818 rosglGetPixelFormat( HDC hdc )
819 {
820 GLDCDATA *dcdata;
821
822 DBGTRACE( "Called!" );
823
824 dcdata = ROSGL_GetPrivateDCData( hdc );
825 if (dcdata == NULL)
826 {
827 DBGPRINT( "Error: ROSGL_GetPrivateDCData failed!" );
828 return 0;
829 }
830
831 return dcdata->pixel_format;
832 }
833
834
835 /*! \brief Get the address for an OpenGL extension function.
836 *
837 * The addresses this function returns are only valid within the same thread
838 * which it was called from.
839 *
840 * \param proc [IN] Name of the function to look for
841 *
842 * \return The address of the proc
843 * \retval NULL Failure
844 */
845 PROC
846 APIENTRY
847 rosglGetProcAddress( LPCSTR proc )
848 {
849 PROC func;
850 GLDRIVERDATA *icd;
851
852 if (OPENGL32_threaddata->glrc == NULL)
853 {
854 DBGPRINT( "Error: No current GLRC!" );
855 SetLastError( ERROR_INVALID_FUNCTION );
856 return NULL;
857 }
858
859 icd = OPENGL32_threaddata->glrc->icd;
860 func = icd->DrvGetProcAddress( proc );
861 if (func != NULL)
862 {
863 DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
864 return func;
865 }
866
867 /* FIXME: Should we return wgl/gl 1.1 functions? */
868 SetLastError( ERROR_PROC_NOT_FOUND );
869 return NULL;
870 }
871
872
873 /*! \brief Make the given GLRC the threads current GLRC for hdc
874 *
875 * \param hdc [IN] Handle for a DC to be drawn on
876 * \param hglrc [IN] Handle for a GLRC to make current
877 *
878 * \retval TRUE Success
879 * \retval FALSE Failure
880 */
881 BOOL
882 APIENTRY
883 rosglMakeCurrent( HDC hdc, HGLRC hglrc )
884 {
885 GLRC *glrc = (GLRC *)hglrc;
886 ICDTable *icdTable = NULL;
887
888 DBGTRACE( "Called!" );
889
890 /* flush current context */
891 if (OPENGL32_threaddata->glrc != NULL)
892 {
893 glFlush();
894 }
895
896 /* check if current context is unset */
897 if (glrc == NULL)
898 {
899 if (OPENGL32_threaddata->glrc != NULL)
900 {
901 glrc = OPENGL32_threaddata->glrc;
902 glrc->icd->DrvReleaseContext( glrc->hglrc );
903 glrc->is_current = FALSE;
904 OPENGL32_threaddata->glrc = NULL;
905 }
906 }
907 else
908 {
909 /* check hdc */
910 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
911 {
912 DBGPRINT( "Error: hdc is not a DC handle!" );
913 SetLastError( ERROR_INVALID_HANDLE );
914 return FALSE;
915 }
916
917 /* check if we know about this glrc */
918 if (!ROSGL_ContainsContext( glrc ))
919 {
920 DBGPRINT( "Error: hglrc not found!" );
921 SetLastError( ERROR_INVALID_HANDLE );
922 return FALSE;
923 }
924
925 /* check if it is available */
926 if (glrc->is_current && glrc->thread_id != GetCurrentThreadId()) /* used by another thread */
927 {
928 DBGPRINT( "Error: hglrc is current for thread 0x%08x", glrc->thread_id );
929 SetLastError( ERROR_INVALID_HANDLE );
930 return FALSE;
931 }
932
933 /* call the ICD */
934 if (glrc->hglrc != NULL)
935 {
936 DBGPRINT( "Info: Calling DrvSetContext!" );
937 SetLastError( ERROR_SUCCESS );
938 icdTable = glrc->icd->DrvSetContext( hdc, glrc->hglrc,
939 ROSGL_SetContextCallBack );
940 if (icdTable == NULL)
941 {
942 DBGPRINT( "Error: DrvSetContext failed (%d)\n", GetLastError() );
943 return FALSE;
944 }
945 DBGPRINT( "Info: DrvSetContext succeeded!" );
946 }
947
948 /* make it current */
949 if (OPENGL32_threaddata->glrc != NULL)
950 OPENGL32_threaddata->glrc->is_current = FALSE;
951 glrc->is_current = TRUE;
952 glrc->thread_id = GetCurrentThreadId();
953 glrc->hdc = hdc;
954 OPENGL32_threaddata->glrc = glrc;
955 }
956
957 if (ROSGL_SetContextCallBack( icdTable ) != ERROR_SUCCESS && icdTable == NULL)
958 {
959 DBGPRINT( "Warning: ROSGL_SetContextCallBack failed!" );
960 }
961
962 return TRUE;
963 }
964
965
966 BOOL
967 APIENTRY
968 rosglRealizeLayerPalette( HDC hdc, int iLayerPlane, BOOL bRealize )
969 {
970 UNIMPLEMENTED;
971 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
972 return FALSE;
973 }
974
975
976 int
977 APIENTRY
978 rosglSetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
979 int cEntries, CONST COLORREF *pcr )
980 {
981 UNIMPLEMENTED;
982 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
983 return 0;
984 }
985
986
987 /*! \brief Set a DCs pixelformat
988 *
989 * \param hdc [IN] Handle to DC for which to set the format
990 * \param iFormat [IN] Index of the pixelformat to set
991 * \param pfd [IN] Not sure what this is for
992 *
993 * \retval TRUE Success
994 * \retval FALSE Failure
995 */
996 BOOL
997 WINAPI
998 rosglSetPixelFormat( HDC hdc, int iFormat, CONST PIXELFORMATDESCRIPTOR *pfd )
999 {
1000 GLDRIVERDATA *icd;
1001 GLDCDATA *dcdata;
1002
1003 DBGTRACE( "Called!" );
1004
1005 /* load ICD */
1006 icd = ROSGL_ICDForHDC( hdc );
1007 if (icd == NULL)
1008 {
1009 DBGPRINT( "Warning: ICDForHDC() failed" );
1010 return FALSE;
1011 }
1012
1013 /* call ICD */
1014 if (!icd->DrvSetPixelFormat( hdc, iFormat/*, pfd*/ ))
1015 {
1016 DBGPRINT( "Warning: DrvSetPixelFormat(format=%d) failed (%d)",
1017 iFormat, GetLastError() );
1018 return FALSE;
1019 }
1020
1021 /* store format in private DC data */
1022 dcdata = ROSGL_GetPrivateDCData( hdc );
1023 if (dcdata == NULL)
1024 {
1025 DBGPRINT( "Error: ROSGL_GetPrivateDCData() failed!" );
1026 return FALSE;
1027 }
1028 dcdata->pixel_format = iFormat;
1029
1030 return TRUE;
1031 }
1032
1033
1034 /*! \brief Enable display-list sharing between multiple GLRCs
1035 *
1036 * This will only work if both GLRCs are from the same driver.
1037 *
1038 * \param hglrc1 [IN] GLRC number 1
1039 * \param hglrc2 [IN] GLRC number 2
1040 *
1041 * \retval TRUE Success
1042 * \retval FALSE Failure
1043 */
1044 BOOL
1045 APIENTRY
1046 rosglShareLists( HGLRC hglrc1, HGLRC hglrc2 )
1047 {
1048 GLRC *glrc1 = (GLRC *)hglrc1;
1049 GLRC *glrc2 = (GLRC *)hglrc2;
1050
1051 /* check glrcs */
1052 if (!ROSGL_ContainsContext( glrc1 ))
1053 {
1054 DBGPRINT( "Error: hglrc1 not found!" );
1055 SetLastError( ERROR_INVALID_HANDLE );
1056 return FALSE;
1057 }
1058 if (!ROSGL_ContainsContext( glrc2 ))
1059 {
1060 DBGPRINT( "Error: hglrc2 not found!" );
1061 SetLastError( ERROR_INVALID_HANDLE );
1062 return FALSE;
1063 }
1064
1065 /* I think this is only possible within one ICD */
1066 if (glrc1->icd != glrc2->icd)
1067 {
1068 DBGPRINT( "Error: hglrc1 and hglrc2 use different ICDs!" );
1069 SetLastError( ERROR_INVALID_HANDLE );
1070 return FALSE;
1071 }
1072
1073 /* share lists (call ICD) */
1074 return glrc1->icd->DrvShareLists( glrc1->hglrc, glrc2->hglrc );
1075 }
1076
1077
1078 /*! \brief Flushes GL and swaps front/back buffer if appropriate
1079 *
1080 * \param hdc [IN] Handle to device context to swap buffers for
1081 *
1082 * \retval TRUE Success
1083 * \retval FALSE Failure
1084 */
1085 BOOL
1086 APIENTRY
1087 rosglSwapBuffers( HDC hdc )
1088 {
1089 GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
1090 DBGTRACE( "Called!" );
1091 if (icd != NULL)
1092 {
1093 DBGPRINT( "Swapping buffers!" );
1094 if (!icd->DrvSwapBuffers( hdc ))
1095 {
1096 DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
1097 return FALSE;
1098 }
1099 return TRUE;
1100 }
1101
1102 /* FIXME: implement own functionality? */
1103 SetLastError( ERROR_INVALID_FUNCTION );
1104 return FALSE;
1105 }
1106
1107
1108 BOOL
1109 APIENTRY
1110 rosglSwapLayerBuffers( HDC hdc, UINT fuPlanes )
1111 {
1112 UNIMPLEMENTED;
1113 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1114 return FALSE;
1115 }
1116
1117
1118 BOOL
1119 APIENTRY
1120 rosglUseFontBitmapsA( HDC hdc, DWORD first, DWORD count, DWORD listBase )
1121 {
1122 UNIMPLEMENTED;
1123 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1124 return FALSE;
1125 }
1126
1127
1128 BOOL
1129 APIENTRY
1130 rosglUseFontBitmapsW( HDC hdc, DWORD first, DWORD count, DWORD listBase )
1131 {
1132 UNIMPLEMENTED;
1133 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1134 return FALSE;
1135 }
1136
1137
1138 BOOL
1139 APIENTRY
1140 rosglUseFontOutlinesA( HDC hdc, DWORD first, DWORD count, DWORD listBase,
1141 FLOAT deviation, FLOAT extrusion, int format,
1142 GLYPHMETRICSFLOAT *pgmf )
1143 {
1144 UNIMPLEMENTED;
1145 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1146 return FALSE;
1147 }
1148
1149
1150 BOOL
1151 APIENTRY
1152 rosglUseFontOutlinesW( HDC hdc, DWORD first, DWORD count, DWORD listBase,
1153 FLOAT deviation, FLOAT extrusion, int format,
1154 GLYPHMETRICSFLOAT *pgmf )
1155 {
1156 UNIMPLEMENTED;
1157 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1158 return FALSE;
1159 }
1160
1161 #ifdef __cplusplus
1162 }; /* extern "C" */
1163 #endif /* __cplusplus */
1164
1165 /* EOF */