SDL-1.2.14
[sdl_omap.git] / src / video / bwindow / SDL_sysvideo.cc
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 /* BWindow based framebuffer implementation */
25
26 #include <unistd.h>
27
28 #include "SDL_BWin.h"
29 #include "SDL_timer.h"
30
31 extern "C" {
32
33 #include "../SDL_sysvideo.h"
34 #include "../../events/SDL_events_c.h"
35 #include "SDL_sysevents_c.h"
36 #include "SDL_sysmouse_c.h"
37 #include "SDL_syswm_c.h"
38 #include "SDL_lowvideo.h"
39 #include "../SDL_yuvfuncs.h"
40 #include "SDL_sysyuv.h"
41 #include "../blank_cursor.h"
42
43 #define BEOS_HIDDEN_SIZE        32      /* starting hidden window size */
44
45 /* Initialization/Query functions */
46 static int BE_VideoInit(_THIS, SDL_PixelFormat *vformat);
47 static SDL_Rect **BE_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
48 static SDL_Surface *BE_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
49 static void BE_UpdateMouse(_THIS);
50 static int BE_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
51 static void BE_VideoQuit(_THIS);
52
53 /* Hardware surface functions */
54 static int BE_AllocHWSurface(_THIS, SDL_Surface *surface);
55 static int BE_LockHWSurface(_THIS, SDL_Surface *surface);
56 static void BE_UnlockHWSurface(_THIS, SDL_Surface *surface);
57 static void BE_FreeHWSurface(_THIS, SDL_Surface *surface);
58
59 static int BE_ToggleFullScreen(_THIS, int fullscreen);
60 static SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display);
61
62 /* OpenGL functions */
63 #if SDL_VIDEO_OPENGL
64 static int BE_GL_LoadLibrary(_THIS, const char *path);
65 static void* BE_GL_GetProcAddress(_THIS, const char *proc);
66 static int BE_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value);
67 static int BE_GL_MakeCurrent(_THIS);
68 static void BE_GL_SwapBuffers(_THIS);
69 #endif
70
71 /* FB driver bootstrap functions */
72
73 static int BE_Available(void)
74 {
75         return(1);
76 }
77
78 static void BE_DeleteDevice(SDL_VideoDevice *device)
79 {
80         SDL_free(device->hidden);
81         SDL_free(device);
82 }
83
84 static SDL_VideoDevice *BE_CreateDevice(int devindex)
85 {
86         SDL_VideoDevice *device;
87
88         /* Initialize all variables that we clean on shutdown */
89         device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
90         if ( device ) {
91                 SDL_memset(device, 0, (sizeof *device));
92                 device->hidden = (struct SDL_PrivateVideoData *)
93                                 SDL_malloc((sizeof *device->hidden));
94         }
95         if ( (device == NULL) || (device->hidden == NULL) ) {
96                 SDL_OutOfMemory();
97                 if ( device ) {
98                         SDL_free(device);
99                 }
100                 return(0);
101         }
102         SDL_memset(device->hidden, 0, (sizeof *device->hidden));
103
104         /* Set the function pointers */
105         /* Initialization/Query functions */
106         device->VideoInit = BE_VideoInit;
107         device->ListModes = BE_ListModes;
108         device->SetVideoMode = BE_SetVideoMode;
109         device->ToggleFullScreen = BE_ToggleFullScreen;
110         device->UpdateMouse = BE_UpdateMouse;
111         device->CreateYUVOverlay = BE_CreateYUVOverlay;
112         device->SetColors = BE_SetColors;
113         device->UpdateRects = NULL;
114         device->VideoQuit = BE_VideoQuit;
115         /* Hardware acceleration functions */
116         device->AllocHWSurface = BE_AllocHWSurface;
117         device->CheckHWBlit = NULL;
118         device->FillHWRect = NULL;
119         device->SetHWColorKey = NULL;
120         device->SetHWAlpha = NULL;
121         device->LockHWSurface = BE_LockHWSurface;
122         device->UnlockHWSurface = BE_UnlockHWSurface;
123         device->FlipHWSurface = NULL;
124         device->FreeHWSurface = BE_FreeHWSurface;
125         /* Gamma support */
126 #if SDL_VIDEO_OPENGL
127         /* OpenGL support */
128         device->GL_LoadLibrary = BE_GL_LoadLibrary;
129         device->GL_GetProcAddress = BE_GL_GetProcAddress;
130         device->GL_GetAttribute = BE_GL_GetAttribute;
131         device->GL_MakeCurrent = BE_GL_MakeCurrent;
132         device->GL_SwapBuffers = BE_GL_SwapBuffers;
133 #endif
134         /* Window manager functions */
135         device->SetCaption = BE_SetWMCaption;
136         device->SetIcon = NULL;
137         device->IconifyWindow = BE_IconifyWindow;
138         device->GrabInput = BE_GrabInput;
139         device->GetWMInfo = BE_GetWMInfo;
140         /* Cursor manager functions */
141         device->FreeWMCursor = BE_FreeWMCursor;
142         device->CreateWMCursor = BE_CreateWMCursor;
143         device->ShowWMCursor = BE_ShowWMCursor;
144         device->WarpWMCursor = BE_WarpWMCursor;
145         device->MoveWMCursor = NULL;
146         device->CheckMouseMode = BE_CheckMouseMode;
147         /* Event manager functions */
148         device->InitOSKeymap = BE_InitOSKeymap;
149         device->PumpEvents = BE_PumpEvents;
150
151         device->free = BE_DeleteDevice;
152
153         /* Set the driver flags */
154         device->handles_any_size = 1;
155         
156         return device;
157 }
158
159 VideoBootStrap BWINDOW_bootstrap = {
160         "bwindow", "BDirectWindow graphics",
161         BE_Available, BE_CreateDevice
162 };
163
164 static inline int ColorSpaceToBitsPerPixel(uint32 colorspace)
165 {
166         int bitsperpixel;
167
168         bitsperpixel = 0;
169         switch (colorspace) {
170             case B_CMAP8:
171                 bitsperpixel = 8;
172                 break;
173             case B_RGB15:
174             case B_RGBA15:
175             case B_RGB15_BIG:
176             case B_RGBA15_BIG:
177                 bitsperpixel = 15;
178                 break;
179             case B_RGB16:
180             case B_RGB16_BIG:
181                 bitsperpixel = 16;
182                 break;
183             case B_RGB32:
184             case B_RGBA32:
185             case B_RGB32_BIG:
186             case B_RGBA32_BIG:
187                 bitsperpixel = 32;
188                 break;
189             default:
190                 break;
191         }
192         return(bitsperpixel);
193 }
194
195 /* Function to sort the display_list in bscreen */
196 static int CompareModes(const void *A, const void *B)
197 {
198         const display_mode *a = (display_mode *)A;
199         const display_mode *b = (display_mode *)B;
200
201         if ( a->space == b->space ) {
202                 return((b->virtual_width*b->virtual_height)-
203                        (a->virtual_width*a->virtual_height));
204         } else {
205                 return(ColorSpaceToBitsPerPixel(b->space)-
206                        ColorSpaceToBitsPerPixel(a->space));
207         }
208 }
209
210 /* Yes, this isn't the fastest it could be, but it works nicely */
211 static int BE_AddMode(_THIS, int index, unsigned int w, unsigned int h)
212 {
213         SDL_Rect *mode;
214         int i;
215         int next_mode;
216
217         /* Check to see if we already have this mode */
218         if ( SDL_nummodes[index] > 0 ) {
219                 for ( i=SDL_nummodes[index]-1; i >= 0; --i ) {
220                         mode = SDL_modelist[index][i];
221                         if ( (mode->w == w) && (mode->h == h) ) {
222 #ifdef BWINDOW_DEBUG
223                                 fprintf(stderr, "We already have mode %dx%d at %d bytes per pixel\n", w, h, index+1);
224 #endif
225                                 return(0);
226                         }
227                 }
228         }
229
230         /* Set up the new video mode rectangle */
231         mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
232         if ( mode == NULL ) {
233                 SDL_OutOfMemory();
234                 return(-1);
235         }
236         mode->x = 0;
237         mode->y = 0;
238         mode->w = w;
239         mode->h = h;
240 #ifdef BWINDOW_DEBUG
241         fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1);
242 #endif
243
244         /* Allocate the new list of modes, and fill in the new mode */
245         next_mode = SDL_nummodes[index];
246         SDL_modelist[index] = (SDL_Rect **)
247                SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
248         if ( SDL_modelist[index] == NULL ) {
249                 SDL_OutOfMemory();
250                 SDL_nummodes[index] = 0;
251                 SDL_free(mode);
252                 return(-1);
253         }
254         SDL_modelist[index][next_mode] = mode;
255         SDL_modelist[index][next_mode+1] = NULL;
256         SDL_nummodes[index]++;
257
258         return(0);
259 }
260
261 int BE_VideoInit(_THIS, SDL_PixelFormat *vformat)
262 {
263         display_mode *modes;
264         uint32 i, nmodes;
265         int bpp;
266         BRect bounds;
267
268         /* Initialize the Be Application for appserver interaction */
269         if ( SDL_InitBeApp() < 0 ) {
270                 return(-1);
271         }
272
273         /* It is important that this be created after SDL_InitBeApp() */
274         BScreen bscreen;
275
276         /* Save the current display mode */
277         bscreen.GetMode(&saved_mode);
278         _this->info.current_w = saved_mode.virtual_width;
279         _this->info.current_h = saved_mode.virtual_height;
280
281         /* Determine the screen depth */
282         vformat->BitsPerPixel = ColorSpaceToBitsPerPixel(bscreen.ColorSpace());
283         if ( vformat->BitsPerPixel == 0 ) {
284                 SDL_SetError("Unknown BScreen colorspace: 0x%x",
285                                                 bscreen.ColorSpace());
286                 return(-1);
287         }
288
289         /* Get the video modes we can switch to in fullscreen mode */
290         bscreen.GetModeList(&modes, &nmodes);
291         SDL_qsort(modes, nmodes, sizeof *modes, CompareModes);
292         for ( i=0; i<nmodes; ++i ) {
293                 bpp = ColorSpaceToBitsPerPixel(modes[i].space);
294                 //if ( bpp != 0 ) { // There are bugs in changing colorspace
295                 if ( modes[i].space == saved_mode.space ) {
296                         BE_AddMode(_this, ((bpp+7)/8)-1,
297                                 modes[i].virtual_width,
298                                 modes[i].virtual_height);
299                 }
300         }
301
302         /* Create the window and view */
303         bounds.top = 0; bounds.left = 0;
304         bounds.right = BEOS_HIDDEN_SIZE;
305         bounds.bottom = BEOS_HIDDEN_SIZE;
306         SDL_Win = new SDL_BWin(bounds);
307
308 #if SDL_VIDEO_OPENGL
309         /* testgl application doesn't load library, just tries to load symbols */
310         /* is it correct? if so we have to load library here */
311         BE_GL_LoadLibrary(_this, NULL);
312 #endif
313
314         /* Create the clear cursor */
315         SDL_BlankCursor = BE_CreateWMCursor(_this, blank_cdata, blank_cmask,
316                         BLANK_CWIDTH, BLANK_CHEIGHT, BLANK_CHOTX, BLANK_CHOTY);
317
318         /* Fill in some window manager capabilities */
319         _this->info.wm_available = 1;
320
321         /* We're done! */
322         return(0);
323 }
324
325 /* We support any dimension at our bit-depth */
326 SDL_Rect **BE_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
327 {
328         SDL_Rect **modes;
329
330         modes = ((SDL_Rect **)0);
331         if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
332                 modes = SDL_modelist[((format->BitsPerPixel+7)/8)-1];
333         } else {
334                 if ( format->BitsPerPixel ==
335                         _this->screen->format->BitsPerPixel ) {
336                         modes = ((SDL_Rect **)-1);
337                 }
338         }
339         return(modes);
340 }
341
342 /* Various screen update functions available */
343 static void BE_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
344
345
346 /* Find the closest display mode for fullscreen */
347 static bool BE_FindClosestFSMode(_THIS, int width, int height, int bpp,
348                                          display_mode *mode)
349 {
350         BScreen bscreen;
351         uint32 i, nmodes;
352         SDL_Rect **modes;
353         display_mode *dmodes;
354         display_mode current;
355         float current_refresh;
356         bscreen.GetMode(&current);
357         current_refresh = (1000 * current.timing.pixel_clock) / 
358                           (current.timing.h_total * current.timing.v_total);
359
360         modes = SDL_modelist[((bpp+7)/8)-1];
361         
362         // find end of list (lowest-resolution mode; modes are ordered
363         // highest-to-lowest).
364         i = 0; while(modes[i]) i++;
365         if (!i) return false;           // what? no modes at all?
366         
367         // find first mode with resolution >= requested in both dimensions
368         for (--i; i >= 0; --i)
369         {
370                 if (modes[i]->w >= width && modes[i]->h >= height)
371                         break;
372         }
373         
374         // unable to find any mode with that high a resolution!
375         if (i < 0)
376                 return false;
377         
378         width = modes[i]->w;
379         height = modes[i]->h;
380
381         bscreen.GetModeList(&dmodes, &nmodes);
382         for ( i = 0; i < nmodes; ++i ) {
383                 if ( (bpp == ColorSpaceToBitsPerPixel(dmodes[i].space)) &&
384                      (width == dmodes[i].virtual_width) &&
385                      (height == dmodes[i].virtual_height) ) {
386                         break;
387                 }
388         }
389         if ( i != nmodes ) {
390                 *mode = dmodes[i];
391                 if ((mode->virtual_width <= current.virtual_width) &&
392                     (mode->virtual_height <= current.virtual_height)) {
393                         float new_refresh = (1000 * mode->timing.pixel_clock) /
394                                             (mode->timing.h_total * mode->timing.v_total);
395                         if (new_refresh < current_refresh) {
396                                 mode->timing.pixel_clock = (uint32)((mode->timing.h_total * mode->timing.v_total)
397                                                                     * current_refresh / 1000);
398                         }
399                 }
400                 return true;
401         } else {
402                 return false;
403         }       
404 }
405
406 static int BE_SetFullScreen(_THIS, SDL_Surface *screen, int fullscreen)
407 {
408         // printf("SetFullScreen(%d)\n", fullscreen);
409         BScreen bscreen;
410
411         // SetFullSscreen() does not work as expected if called in a window
412         // that was never shown. This is probably a bug in the Haiku Game Kit that needs
413         // to be investigated.  
414         if (SDL_Win->Lock()) {
415                 // Show our window.
416                 SDL_Win->Show();
417         }       
418         
419         if (SDL_Win->IsLocked()) {
420                 // Unlock the window if it was locked. This is needed as only the
421                 // first call to Show() unlocks the looper. All other calls to it
422                 // will not.
423                 SDL_Win->Unlock();
424         }
425
426         int width = screen->w;
427         int height = screen->h;
428         
429         if (fullscreen) {
430                 // Set resolution to the closest available one that matches the
431                 // current SDL resolution.
432                 display_mode mode;
433                 bscreen.GetMode(&mode);
434
435                 int bpp = screen->format->BitsPerPixel;
436                 if (bpp != ColorSpaceToBitsPerPixel(mode.space) ||
437                         width != mode.virtual_width || height != mode.virtual_height) {
438                         if(BE_FindClosestFSMode(_this, width, height, bpp, &mode)) {
439                                 bscreen.SetMode(&mode);
440                         } else {
441                                 // printf("Could not set new mode.\n");
442                                 return(0);
443                         }                       
444                 }
445         } else {
446                 // Reset to the previous known resolution as we are now in window
447                 // mode.
448                 bscreen.SetMode(&saved_mode);   
449         }
450         
451         // Effectivelly set/reset full screen mode. If we are already in
452         // full screen mode, we reset back to windowed mode first so the
453         // window can resize when going fullscreen.
454         // if (fullscreen)
455                 // printf("Going fullscreen\n");
456         // else
457                 // printf("Going windowed\n"); 
458         SDL_Win->SetFullScreen(fullscreen);
459         
460         // Calculate offsets for centering the window (in window mode) and for
461         // dentering the bitmap (in full screen mode).
462         BRect bounds = bscreen.Frame();
463         bounds.PrintToStream();
464         int32 cx = (bounds.IntegerWidth() - width)/2;
465         int32 cy = (bounds.IntegerHeight() - height)/2;
466         
467         // printf ("cx = %d, cy = %d\n", cx, cy);
468         if (!SDL_Win->IsFullScreen()) {
469                 // printf("Doing not fullscreen stuff.\n");
470                 // We are not in full screen mode, so we want to change the window
471                 // size to match the resolution in SDL.
472                 SDL_Win->ResizeTo(width, height);
473                 
474                 // And also center the window and reset the drawing offset.
475                 SDL_Win->MoveTo(cx, cy);
476                 SDL_Win->SetXYOffset(0, 0);
477         } else {
478                 // printf("Doing fullscreen stuff.");
479                 // Center the bitmap whenever we are in full screen mode.
480                 SDL_Win->SetXYOffset(cx, cy);
481         }
482         
483         // Set relevant internal SDL screen flags.
484         if (SDL_Win->IsFullScreen()) {
485                 screen->flags |= SDL_FULLSCREEN;
486         } else {
487                 screen->flags &= ~SDL_FULLSCREEN; 
488         }
489
490         return(1);
491 }
492
493 static int BE_ToggleFullScreen(_THIS, int fullscreen)
494 {
495         return BE_SetFullScreen(_this, _this->screen, fullscreen);
496 }
497
498 /* FIXME: check return values and cleanup here */
499 SDL_Surface *BE_SetVideoMode(_THIS, SDL_Surface *current,
500                                 int width, int height, int bpp, Uint32 flags)
501 {
502         BScreen bscreen;
503         BBitmap *bbitmap;
504         BRect bounds;
505         Uint32 gl_flags = 0;
506
507         /* Only RGB works on r5 currently */
508         gl_flags = BGL_RGB;
509         if (_this->gl_config.double_buffer)
510                 gl_flags |= BGL_DOUBLE;
511         else
512                 gl_flags |= BGL_SINGLE;
513         if (_this->gl_config.alpha_size > 0 || bpp == 32)
514                 gl_flags |= BGL_ALPHA;
515         if (_this->gl_config.depth_size > 0)
516                 gl_flags |= BGL_DEPTH;
517         if (_this->gl_config.stencil_size > 0)
518                 gl_flags |= BGL_STENCIL;
519         if (_this->gl_config.accum_red_size > 0
520                 || _this->gl_config.accum_green_size > 0
521                 || _this->gl_config.accum_blue_size > 0
522                 || _this->gl_config.accum_alpha_size > 0)
523                 gl_flags |= BGL_ACCUM;
524
525         /* Create the view for this window, using found flags */
526         if ( SDL_Win->CreateView(flags, gl_flags) < 0 ) {
527                 return(NULL);
528         }
529
530         current->flags = 0;             /* Clear flags */
531         current->w = width;
532         current->h = height;
533         SDL_Win->SetType(B_TITLED_WINDOW);
534         if ( flags & SDL_NOFRAME ) {
535                 current->flags |= SDL_NOFRAME;
536                 SDL_Win->SetLook(B_NO_BORDER_WINDOW_LOOK);
537         } else {
538                 if ( (flags & SDL_RESIZABLE) && !(flags & SDL_OPENGL) )  {
539                         current->flags |= SDL_RESIZABLE;
540                         /* We don't want opaque resizing (TM). :-) */
541                         SDL_Win->SetFlags(B_OUTLINE_RESIZE);
542                 } else {
543                         SDL_Win->SetFlags(B_NOT_RESIZABLE|B_NOT_ZOOMABLE);
544                 }
545         }
546
547         if ( flags & SDL_OPENGL ) {
548                 current->flags |= SDL_OPENGL;
549                 current->pitch = 0;
550                 current->pixels = NULL;
551                 _this->UpdateRects = NULL;
552         } else {
553                 /* Create the BBitmap framebuffer */
554                 bounds.top = 0; bounds.left = 0;
555                 bounds.right = width-1;
556                 bounds.bottom = height-1;
557                 bbitmap = new BBitmap(bounds, bscreen.ColorSpace());
558                 if ( ! bbitmap->IsValid() ) {
559                         SDL_SetError("Couldn't create screen bitmap");
560                         delete bbitmap;
561                         return(NULL);
562                 }
563                 current->pitch = bbitmap->BytesPerRow();
564                 current->pixels = (void *)bbitmap->Bits();
565                 SDL_Win->SetBitmap(bbitmap);
566                 _this->UpdateRects = BE_NormalUpdate;
567         }
568
569         /* Set the correct fullscreen mode */
570         BE_SetFullScreen(_this, current, flags & SDL_FULLSCREEN ? 1 : 0);
571
572         /* We're done */
573         return(current);
574 }
575
576 /* Update the current mouse state and position */
577 void BE_UpdateMouse(_THIS)
578 {
579         BPoint point;
580         uint32 buttons;
581
582         if ( SDL_Win->Lock() ) {
583                 /* Get new input state, if still active */
584                 if ( SDL_Win->IsActive() ) {
585                         (SDL_Win->View())->GetMouse(&point, &buttons, true);
586                 } else {
587                         point.x = -1;
588                         point.y = -1;
589                 }
590                 SDL_Win->Unlock();
591
592                 if ( (point.x >= 0) && (point.x < SDL_VideoSurface->w) &&
593                      (point.y >= 0) && (point.y < SDL_VideoSurface->h) ) {
594                         SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
595                         SDL_PrivateMouseMotion(0, 0,
596                                         (Sint16)point.x, (Sint16)point.y);
597                 } else {
598                         SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
599                 }
600         }
601 }
602
603 /* We don't actually allow hardware surfaces other than the main one */
604 static int BE_AllocHWSurface(_THIS, SDL_Surface *surface)
605 {
606         return(-1);
607 }
608 static void BE_FreeHWSurface(_THIS, SDL_Surface *surface)
609 {
610         return;
611 }
612 static int BE_LockHWSurface(_THIS, SDL_Surface *surface)
613 {
614         return(0);
615 }
616 static void BE_UnlockHWSurface(_THIS, SDL_Surface *surface)
617 {
618         return;
619 }
620
621 static void BE_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
622 {
623         if ( SDL_Win->BeginDraw() ) {
624                 int i;
625
626                 for ( i=0; i<numrects; ++i ) {
627                         BRect rect;
628
629                         rect.top = rects[i].y;
630                         rect.left = rects[i].x;
631                         rect.bottom = rect.top+rects[i].h-1;
632                         rect.right = rect.left+rects[i].w-1;
633                         SDL_Win->DrawAsync(rect);
634                 }
635                 SDL_Win->EndDraw();
636         }
637 }
638
639 #if SDL_VIDEO_OPENGL
640 /* Passing a NULL path means load pointers from the application */
641 int BE_GL_LoadLibrary(_THIS, const char *path)
642 {
643         if (path == NULL) {
644                 if (_this->gl_config.dll_handle == NULL) {
645                         image_info info;
646                         int32 cookie = 0;
647                         while (get_next_image_info(0,&cookie,&info) == B_OK) {
648                                 void *location = NULL;
649 #ifdef __HAIKU__
650                                 if (get_image_symbol(info.id,"glBegin",B_SYMBOL_TYPE_ANY,&location) == B_OK) { // This is how it actually works in Haiku
651 #else
652                                 if (get_image_symbol((image_id)cookie,"glBegin",B_SYMBOL_TYPE_ANY,&location) == B_OK) { // I don't know if that *did* work in BeOS
653 #endif
654                                         _this->gl_config.dll_handle = (void*)info.id;
655                                         _this->gl_config.driver_loaded = 1;
656                                         SDL_strlcpy(_this->gl_config.driver_path, "libGL.so", SDL_arraysize(_this->gl_config.driver_path));
657                                 }
658                         }
659                 }
660         } else {
661                 /*
662                         FIXME None of BeOS libGL.so implementations have exported functions 
663                         to load BGLView, which should be reloaded from new lib.
664                         So for now just "load" linked libGL.so :(
665                 */
666                 if (_this->gl_config.dll_handle == NULL) {
667                         return BE_GL_LoadLibrary(_this, NULL);
668                 }
669
670                 /* Unload old first */
671                 /*if (_this->gl_config.dll_handle != NULL) {*/
672                         /* Do not try to unload application itself (if LoadLibrary was called before with NULL ;) */
673                 /*      image_info info;
674                         if (get_image_info((image_id)_this->gl_config.dll_handle, &info) == B_OK) {
675                                 if (info.type != B_APP_IMAGE) {
676                                         unload_add_on((image_id)_this->gl_config.dll_handle);
677                                 }
678                         }
679                         
680                 }
681
682                 if ((_this->gl_config.dll_handle = (void*)load_add_on(path)) != (void*)B_ERROR) {
683                         _this->gl_config.driver_loaded = 1;
684                         SDL_strlcpy(_this->gl_config.driver_path, path, SDL_arraysize(_this->gl_config.driver_path));
685                 }*/
686         }
687
688         if (_this->gl_config.dll_handle != NULL) {
689                 return 0;
690         } else {
691                 _this->gl_config.dll_handle = NULL;
692                 _this->gl_config.driver_loaded = 0;
693                 *_this->gl_config.driver_path = '\0';
694                 return -1;
695         }
696 }
697
698 void* BE_GL_GetProcAddress(_THIS, const char *proc)
699 {
700         if (_this->gl_config.dll_handle != NULL) {
701                 void *location = NULL;
702                 status_t err;
703                 if ((err = get_image_symbol((image_id)_this->gl_config.dll_handle, proc, B_SYMBOL_TYPE_ANY, &location)) == B_OK) {
704                         return location;
705                 } else {
706                         SDL_SetError("Couldn't find OpenGL symbol");
707                         return NULL;
708                 }
709         } else {
710                 SDL_SetError("OpenGL library not loaded");
711                 return NULL;
712         }
713 }
714
715 int BE_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
716 {
717         /*
718                 FIXME? Right now BE_GL_GetAttribute shouldn't be called between glBegin() and glEnd() - it doesn't use "cached" values
719         */
720         switch (attrib)
721     {
722                 case SDL_GL_RED_SIZE:
723                         glGetIntegerv(GL_RED_BITS, (GLint*)value);
724                         break;
725                 case SDL_GL_GREEN_SIZE:
726                         glGetIntegerv(GL_GREEN_BITS, (GLint*)value);
727                         break;
728                 case SDL_GL_BLUE_SIZE:
729                         glGetIntegerv(GL_BLUE_BITS, (GLint*)value);
730                         break;
731                 case SDL_GL_ALPHA_SIZE:
732                         glGetIntegerv(GL_ALPHA_BITS, (GLint*)value);
733                         break;
734                 case SDL_GL_DOUBLEBUFFER:
735                         glGetBooleanv(GL_DOUBLEBUFFER, (GLboolean*)value);
736                         break;
737                 case SDL_GL_BUFFER_SIZE:
738                         int v;
739                         glGetIntegerv(GL_RED_BITS, (GLint*)&v);
740                         *value = v;
741                         glGetIntegerv(GL_GREEN_BITS, (GLint*)&v);
742                         *value += v;
743                         glGetIntegerv(GL_BLUE_BITS, (GLint*)&v);
744                         *value += v;
745                         glGetIntegerv(GL_ALPHA_BITS, (GLint*)&v);
746                         *value += v;
747                         break;
748                 case SDL_GL_DEPTH_SIZE:
749                         glGetIntegerv(GL_DEPTH_BITS, (GLint*)value); /* Mesa creates 16 only? r5 always 32 */
750                         break;
751                 case SDL_GL_STENCIL_SIZE:
752                         glGetIntegerv(GL_STENCIL_BITS, (GLint*)value);
753                         break;
754                 case SDL_GL_ACCUM_RED_SIZE:
755                         glGetIntegerv(GL_ACCUM_RED_BITS, (GLint*)value);
756                         break;
757                 case SDL_GL_ACCUM_GREEN_SIZE:
758                         glGetIntegerv(GL_ACCUM_GREEN_BITS, (GLint*)value);
759                         break;
760                 case SDL_GL_ACCUM_BLUE_SIZE:
761                         glGetIntegerv(GL_ACCUM_BLUE_BITS, (GLint*)value);
762                         break;
763                 case SDL_GL_ACCUM_ALPHA_SIZE:
764                         glGetIntegerv(GL_ACCUM_ALPHA_BITS, (GLint*)value);
765                         break;
766                 case SDL_GL_STEREO:
767                 case SDL_GL_MULTISAMPLEBUFFERS:
768                 case SDL_GL_MULTISAMPLESAMPLES:
769                 default:
770                         *value=0;
771                         return(-1);
772         }
773         return 0;
774 }
775
776 int BE_GL_MakeCurrent(_THIS)
777 {
778         /* FIXME: should we glview->unlock and then glview->lock()? */
779         return 0;
780 }
781
782 void BE_GL_SwapBuffers(_THIS)
783 {
784         SDL_Win->SwapBuffers();
785 }
786 #endif
787
788 /* Is the system palette settable? */
789 int BE_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
790 {
791         int i;
792         SDL_Palette *palette;
793         const color_map *cmap = BScreen().ColorMap();
794
795         /* Get the screen colormap */
796         palette = _this->screen->format->palette;
797         for ( i=0; i<256; ++i ) {
798                 palette->colors[i].r = cmap->color_list[i].red;
799                 palette->colors[i].g = cmap->color_list[i].green;
800                 palette->colors[i].b = cmap->color_list[i].blue;
801         }
802         return(0);
803 }
804
805 void BE_VideoQuit(_THIS)
806 {
807         int i, j;
808
809         SDL_Win->Quit();
810         SDL_Win = NULL;
811
812         if ( SDL_BlankCursor != NULL ) {
813                 BE_FreeWMCursor(_this, SDL_BlankCursor);
814                 SDL_BlankCursor = NULL;
815         }
816         for ( i=0; i<NUM_MODELISTS; ++i ) {
817                 if ( SDL_modelist[i] ) {
818                         for ( j=0; SDL_modelist[i][j]; ++j ) {
819                                 SDL_free(SDL_modelist[i][j]);
820                         }
821                         SDL_free(SDL_modelist[i]);
822                         SDL_modelist[i] = NULL;
823                 }
824         }
825         /* Restore the original video mode */
826         if ( _this->screen ) {
827                 if ( (_this->screen->flags&SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
828                         BScreen bscreen;
829                         bscreen.SetMode(&saved_mode);
830                 }
831                 _this->screen->pixels = NULL;
832         }
833
834 #if SDL_VIDEO_OPENGL
835         if (_this->gl_config.dll_handle != NULL)
836                 unload_add_on((image_id)_this->gl_config.dll_handle);
837 #endif
838
839         SDL_QuitBeApp();
840 }
841
842 }; /* Extern C */