SDL 1.2.13
[crawl:crawl-sdl.git] / src / video / riscos / SDL_riscosFullScreenVideo.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2004 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 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     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public
16     License along with this library; if not, write to the Free
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 /*
25      File added by Alan Buckley (alan_baa@hotmail.com) for RISC OS compatability
26          27 March 2003
27
28      Implements RISC OS full screen display.
29 */
30
31 #include "SDL_video.h"
32 #include "SDL_mouse.h"
33 #include "../SDL_sysvideo.h"
34 #include "../SDL_pixels_c.h"
35 #include "../../events/SDL_events_c.h"
36
37 #include "SDL_riscostask.h"
38 #include "SDL_riscosvideo.h"
39 #include "SDL_riscosevents_c.h"
40 #include "SDL_riscosmouse_c.h"
41
42 #include "kernel.h"
43 #include "swis.h"
44 #include "unixlib/os.h"
45 #include "unixlib/local.h"
46
47 /* Private structures */
48 typedef struct tagScreenModeBlock
49 {
50    int flags;  // mode selector flags, bit 0 = 1, bit 1-7 format specifier, 8-31 reserved
51    int x_pixels;
52    int y_pixels;
53    int pixel_depth;  // 2^pixel_depth = bpp,i.e. 0 = 1, 1 = 2, 4 = 16, 5 = 32
54    int frame_rate;   // -1 use first match
55    int mode_vars[5]; // array of index, value pairs terminated by -1
56 } SCREENMODEBLOCK;
57
58
59 /* Helper functions */
60 void FULLSCREEN_SetDeviceMode(_THIS);
61 int FULLSCREEN_SetMode(int width, int height, int bpp);
62 void FULLSCREEN_SetupBanks(_THIS);
63
64 /* SDL video device functions for fullscreen mode */
65 static int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
66 static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface);
67 void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon);
68 extern int RISCOS_GetWmInfo(_THIS, SDL_SysWMinfo *info);
69
70 /* UpdateRects variants */
71 static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
72 static void FULLSCREEN_UpdateRectsMemCpy(_THIS, int numrects, SDL_Rect *rects);
73 static void FULLSCREEN_UpdateRects8bpp(_THIS, int numrects, SDL_Rect *rects);
74 static void FULLSCREEN_UpdateRects16bpp(_THIS, int numrects, SDL_Rect *rects);
75 static void FULLSCREEN_UpdateRects32bpp(_THIS, int numrects, SDL_Rect *rects);
76 static void FULLSCREEN_UpdateRectsOS(_THIS, int numrects, SDL_Rect *rects);
77
78 /* Local helper functions */
79 static int cmpmodes(const void *va, const void *vb);
80 static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h);
81 void FULLSCREEN_SetWriteBank(int bank);
82 void FULLSCREEN_SetDisplayBank(int bank);
83 static void FULLSCREEN_DisableEscape();
84 static void FULLSCREEN_EnableEscape();
85 void FULLSCREEN_BuildModeList(_THIS);
86
87 /* Following variable is set up in riskosTask.c */
88 extern int riscos_backbuffer; /* Create a back buffer in system memory for full screen mode */
89
90 /* Following is used to create a sprite back buffer */
91 extern unsigned char *WIMP_CreateBuffer(int width, int height, int bpp);
92
93 /* Fast assembler copy */
94 extern void RISCOS_Put32(void *to, int pixels, int pitch, int rows, void *from, int src_skip_bytes);
95
96 SDL_Surface *FULLSCREEN_SetVideoMode(_THIS, SDL_Surface *current,
97                                 int width, int height, int bpp, Uint32 flags)
98 {
99    _kernel_swi_regs regs;
100    Uint32 Rmask = 0;
101    Uint32 Gmask = 0;
102    Uint32 Bmask = 0;
103    int create_back_buffer = riscos_backbuffer;
104
105    switch(bpp)
106    {
107         case 8:
108                 flags |= SDL_HWPALETTE;
109                 break;
110
111         case 15:
112         case 16:
113                 Bmask = 0x00007c00;
114                 Gmask = 0x000003e0;
115                 Rmask = 0x0000001f;
116                 break;
117
118         case 32:
119                 Bmask = 0x00ff0000;
120                 Gmask = 0x0000ff00;
121                 Rmask = 0x000000ff;
122                 break;
123
124         default:
125                 SDL_SetError("Pixel depth not supported");
126                 return NULL;
127                 break;
128    }
129
130    if (FULLSCREEN_SetMode(width, height, bpp) == 0)
131    {
132            SDL_SetError("Couldn't set requested mode");
133            return (NULL);
134    }
135
136 /*      printf("Setting mode %dx%d\n", width, height); */
137
138         /* Allocate the new pixel format for the screen */
139         if ( ! SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0) ) {
140             RISCOS_RestoreWimpMode();
141                 SDL_SetError("Couldn't allocate new pixel format for requested mode");
142                 return(NULL);
143         }
144
145         /* Set up the new mode framebuffer */
146         current->w = width;
147         this->hidden->height = current->h = height;
148
149    regs.r[0] = -1; /* -1 for current screen mode */
150
151    /* Get screen width in bytes */
152    regs.r[1] = 6; // Screen Width in bytes
153    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
154
155    current->pitch = regs.r[2];
156
157    if (flags & SDL_DOUBLEBUF)
158    {
159            regs.r[0] = 2; /* Screen area */
160            _kernel_swi(OS_ReadDynamicArea, &regs, &regs);
161            
162            /* Reg 1 has amount of memory currently used for display */
163            regs.r[0] = 2; /* Screen area */
164            regs.r[1] = (current->pitch * height * 2) - regs.r[1];
165            if (_kernel_swi(OS_ChangeDynamicArea, &regs, &regs) != NULL)
166            {
167                    /* Can't allocate enough screen memory for double buffer */
168                    flags &= ~SDL_DOUBLEBUF;
169            }
170    }
171    
172         current->flags = flags | SDL_FULLSCREEN | SDL_HWSURFACE | SDL_PREALLOC;
173         
174
175         /* Need to set display banks here for double buffering */
176         if (flags & SDL_DOUBLEBUF)
177         {
178            FULLSCREEN_SetWriteBank(0);
179            FULLSCREEN_SetDisplayBank(1);
180
181          create_back_buffer = 0; /* Don't need a back buffer for a double buffered display */
182     }
183
184     FULLSCREEN_SetupBanks(this);
185
186     if (create_back_buffer)
187     {
188        /* If not double buffered we may need to create a memory
189          ** back buffer to simulate processing on other OSes.
190          ** This is turned on by setting the enviromental variable
191          ** SDL$<name>$BackBuffer >= 1
192          */
193        if (riscos_backbuffer == 3)
194           this->hidden->bank[0] = WIMP_CreateBuffer(width, height, bpp);
195        else
196           this->hidden->bank[0] = SDL_malloc(height * current->pitch);
197        if (this->hidden->bank[0] == 0)
198        {
199                RISCOS_RestoreWimpMode();
200            SDL_SetError("Couldnt allocate memory for back buffer");
201            return (NULL);
202        }
203        /* Surface updated in programs is now a software surface */
204        current->flags &= ~SDL_HWSURFACE;
205     }
206
207     /* Store address of allocated screen bank to be freed later */
208     if (this->hidden->alloc_bank) SDL_free(this->hidden->alloc_bank);
209     if (create_back_buffer)
210     {
211         this->hidden->alloc_bank = this->hidden->bank[0];
212         if (riscos_backbuffer == 3)
213         {
214            this->hidden->bank[0] += 60; /* Start of sprite data */
215            if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
216         }
217     } else
218           this->hidden->alloc_bank = 0;
219
220     // Clear both banks to black
221     SDL_memset(this->hidden->bank[0], 0, height * current->pitch);
222     SDL_memset(this->hidden->bank[1], 0, height * current->pitch);
223
224            this->hidden->current_bank = 0;
225            current->pixels = this->hidden->bank[0];
226
227     /* Have to set the screen here, so SetDeviceMode will pick it up */
228     this->screen = current;
229
230         /* Reset device functions for the wimp */
231         FULLSCREEN_SetDeviceMode(this);
232
233 /*      FULLSCREEN_DisableEscape(); */
234
235         /* We're done */
236         return(current);
237 }
238
239 /* Reset any device functions that have been changed because we have run in WIMP mode */
240 void FULLSCREEN_SetDeviceMode(_THIS)
241 {
242         /* Update rects is different if we have a backbuffer */
243
244         if (riscos_backbuffer && (this->screen->flags & SDL_DOUBLEBUF) == 0)
245       {
246            switch(riscos_backbuffer)
247          {
248             case 2: /* ARM code full word copy */
249                switch(this->screen->format->BytesPerPixel)
250                {
251                   case 1: /* 8bpp modes */
252                    this->UpdateRects = FULLSCREEN_UpdateRects8bpp;
253                      break;
254                   case 2: /* 15/16bpp modes */
255                    this->UpdateRects = FULLSCREEN_UpdateRects16bpp;
256                      break;
257                   case 4: /* 32 bpp modes */
258                    this->UpdateRects = FULLSCREEN_UpdateRects32bpp;
259                      break;
260
261                   default: /* Just default to the memcpy routine */
262                    this->UpdateRects = FULLSCREEN_UpdateRectsMemCpy;
263                      break;
264                 }
265                break;
266
267             case 3: /* Use OS sprite plot routine */
268                this->UpdateRects = FULLSCREEN_UpdateRectsOS;
269                break;
270
271             default: /* Old but safe memcpy */
272                this->UpdateRects = FULLSCREEN_UpdateRectsMemCpy;
273                break;
274          }
275       } else
276            this->UpdateRects = FULLSCREEN_UpdateRects; /* Default do nothing implementation */
277
278         this->SetColors   = FULLSCREEN_SetColors;
279
280         this->FlipHWSurface = FULLSCREEN_FlipHWSurface;
281
282         this->SetCaption = FULLSCREEN_SetWMCaption;
283         this->SetIcon = NULL;
284         this->IconifyWindow = NULL;
285         
286         this->ShowWMCursor = RISCOS_ShowWMCursor;
287         this->WarpWMCursor = FULLSCREEN_WarpWMCursor;
288
289         this->PumpEvents = FULLSCREEN_PumpEvents;       
290 }
291
292 /* Query for the list of available video modes */
293 void FULLSCREEN_BuildModeList(_THIS)
294 {
295         _kernel_swi_regs regs;
296         char *enumInfo = NULL;
297         char *enum_ptr;
298         int *blockInfo;
299         int j;
300         int num_modes;
301
302         /* Find out how much space we need */
303         regs.r[0] = 2; /* Reason code */
304         regs.r[2] = 0; /* Number of modes to skip */
305         regs.r[6] = 0; /* pointer to block or 0 for count */
306         regs.r[7] = 0; /* Size of block in bytes */
307         _kernel_swi(OS_ScreenMode, &regs, &regs);
308
309     num_modes = -regs.r[2];
310
311         /* Video memory should be in r[5] */
312         this->info.video_mem = regs.r[5]/1024;
313
314         enumInfo = (unsigned char *)SDL_malloc(-regs.r[7]);
315         if (enumInfo == NULL)
316         {
317                 SDL_OutOfMemory();
318                 return;
319         }
320         /* Read mode information into block */
321         regs.r[2] = 0;
322         regs.r[6] = (int)enumInfo;
323         regs.r[7] = -regs.r[7];
324         _kernel_swi(OS_ScreenMode, &regs, &regs);
325
326         enum_ptr = enumInfo;
327
328         for (j =0; j < num_modes;j++)
329         {
330                 blockInfo = (int *)enum_ptr;
331                 if ((blockInfo[1] & 255) == 1) /* We understand this format */
332                 {
333                         switch(blockInfo[4])
334                         {
335                         case 3: /* 8 bits per pixel */
336                                 FULLSCREEN_AddMode(this, 8, blockInfo[2], blockInfo[3]);
337                                 break;
338                         case 4: /* 15 bits per pixel */
339                                 FULLSCREEN_AddMode(this, 15, blockInfo[2], blockInfo[3]);
340                                 break;
341                         case 5: /* 32 bits per pixel */
342                                 FULLSCREEN_AddMode(this, 32, blockInfo[2], blockInfo[3]);
343                                 break;
344                         }
345                 }
346
347                 enum_ptr += blockInfo[0];
348         }
349
350         SDL_free(enumInfo);
351                 
352         /* Sort the mode lists */
353         for ( j=0; j<NUM_MODELISTS; ++j ) {
354                 if ( SDL_nummodes[j] > 0 ) {
355                         SDL_qsort(SDL_modelist[j], SDL_nummodes[j], sizeof *SDL_modelist[j], cmpmodes);
356                 }
357         }
358 }
359
360 static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface)
361 {
362    _kernel_swi_regs regs;
363    regs.r[0] = 19;
364
365    FULLSCREEN_SetDisplayBank(this->hidden->current_bank);
366    this->hidden->current_bank ^= 1;
367    FULLSCREEN_SetWriteBank(this->hidden->current_bank);
368    surface->pixels = this->hidden->bank[this->hidden->current_bank];
369
370    /* Wait for Vsync */
371    _kernel_swi(OS_Byte, &regs, &regs);
372
373         return(0);
374 }
375
376 /* Nothing to do if we are writing direct to hardware */
377 static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
378 {
379 }
380
381 /* Safe but slower Memory copy from our allocated back buffer */
382 static void FULLSCREEN_UpdateRectsMemCpy(_THIS, int numrects, SDL_Rect *rects)
383 {
384       int j;
385       char *to, *from;
386       int pitch = this->screen->pitch;
387       int row;
388       int xmult = this->screen->format->BytesPerPixel;
389       for (j = 0; j < numrects; j++)
390       {
391          from = this->hidden->bank[0] + rects->x * xmult + rects->y * pitch;
392          to  = this->hidden->bank[1] + rects->x * xmult + rects->y * pitch;
393          for (row = 0; row < rects->h; row++)
394          {
395              SDL_memcpy(to, from, rects->w * xmult);
396              from += pitch;
397              to += pitch;
398          }
399          rects++;
400       }
401 }
402
403 /* Use optimized assembler memory copy. Deliberately copies extra columns if
404    necessary to ensure the rectangle is word aligned. */
405 static void FULLSCREEN_UpdateRects8bpp(_THIS, int numrects, SDL_Rect *rects)
406 {
407    int j;
408    char *to, *from;
409    int pitch = this->screen->pitch;
410    int width_bytes;
411    int src_skip_bytes;
412
413    for (j = 0; j < numrects; j++)
414    {
415       from = this->hidden->bank[0] + rects->x + rects->y * pitch;
416       to  = this->hidden->bank[1] + rects->x + rects->y * pitch;
417       width_bytes = rects->w;
418       if ((int)from & 3)
419       {
420          int extra = ((int)from & 3);
421          from -= extra;
422          to -= extra;
423          width_bytes += extra;
424       }
425       if (width_bytes & 3) width_bytes += 4 - (width_bytes & 3);
426       src_skip_bytes = pitch - width_bytes;
427                
428       RISCOS_Put32(to, (width_bytes >> 2), pitch, (int)rects->h, from, src_skip_bytes);
429       rects++;
430    }
431 }
432
433 /* Use optimized assembler memory copy. Deliberately copies extra columns if
434    necessary to ensure the rectangle is word aligned. */
435 static void FULLSCREEN_UpdateRects16bpp(_THIS, int numrects, SDL_Rect *rects)
436 {
437    int j;
438    char *to, *from;
439    int pitch = this->screen->pitch;
440    int width_bytes;
441    int src_skip_bytes;
442
443    for (j = 0; j < numrects; j++)
444    {
445       from = this->hidden->bank[0] + (rects->x << 1) + rects->y * pitch;
446       to  = this->hidden->bank[1] + (rects->x << 1) + rects->y * pitch;
447       width_bytes = (((int)rects->w) << 1);
448       if ((int)from & 3)
449       {
450          from -= 2;
451          to -= 2;
452          width_bytes += 2;
453       }
454       if (width_bytes & 3) width_bytes += 2;
455       src_skip_bytes = pitch - width_bytes;
456                
457       RISCOS_Put32(to, (width_bytes >> 2), pitch, (int)rects->h, from, src_skip_bytes);
458       rects++;
459    }
460 }
461
462 /* Use optimized assembler memory copy. 32 bpp modes are always word aligned */
463 static void FULLSCREEN_UpdateRects32bpp(_THIS, int numrects, SDL_Rect *rects)
464 {
465    int j;
466    char *to, *from;
467    int pitch = this->screen->pitch;
468    int width;
469
470    for (j = 0; j < numrects; j++)
471    {
472       from = this->hidden->bank[0] + (rects->x << 2) + rects->y * pitch;
473       to  = this->hidden->bank[1] + (rects->x << 2) + rects->y * pitch;
474       width = (int)rects->w ;
475                
476       RISCOS_Put32(to, width, pitch, (int)rects->h, from, pitch - (width << 2));
477       rects++;
478    }
479 }
480
481 /* Use operating system sprite plots. Currently this is much slower than the
482    other variants however accelerated sprite plotting can be seen on the horizon
483    so this prepares for it. */
484 static void FULLSCREEN_UpdateRectsOS(_THIS, int numrects, SDL_Rect *rects)
485 {
486    _kernel_swi_regs regs;
487    _kernel_oserror *err;
488    int j;
489    int y;
490
491    regs.r[0] = 28 + 512;
492    regs.r[1] = (unsigned int)this->hidden->alloc_bank;
493    regs.r[2] = (unsigned int)this->hidden->alloc_bank+16;
494    regs.r[5] = 0;
495
496    for (j = 0; j < numrects; j++)
497    {
498       y = this->screen->h - rects->y; /* top of clipping region */
499       _kernel_oswrch(24); /* Set graphics clip region */
500       _kernel_oswrch((rects->x << this->hidden->xeig) & 0xFF); /* left */
501       _kernel_oswrch(((rects->x << this->hidden->xeig) >> 8) & 0xFF);
502       _kernel_oswrch(((y - rects->h) << this->hidden->yeig) & 0xFF); /* bottom */
503       _kernel_oswrch((((y - rects->h) << this->hidden->yeig)>> 8) & 0xFF);
504       _kernel_oswrch(((rects->x + rects->w - 1) << this->hidden->xeig) & 0xFF); /* right */
505       _kernel_oswrch((((rects->x + rects->w - 1)<< this->hidden->xeig) >> 8) & 0xFF);
506       _kernel_oswrch(((y-1) << this->hidden->yeig) & 0xFF); /* top */
507       _kernel_oswrch((((y-1) << this->hidden->yeig) >> 8) & 0xFF);
508
509       regs.r[3] = 0;
510       regs.r[4] = 0;
511
512       if ((err = _kernel_swi(OS_SpriteOp, &regs, &regs)) != 0)
513       {
514          printf("OS_SpriteOp failed \n%s\n",err->errmess);
515       }
516
517       rects++;
518
519       /* Reset to full screen clipping */
520       _kernel_oswrch(24); /* Set graphics clip region */
521       _kernel_oswrch(0); /* left */
522       _kernel_oswrch(0);
523       _kernel_oswrch(0); /* bottom */
524       _kernel_oswrch(0);
525       _kernel_oswrch(((this->screen->w-1) << this->hidden->xeig) & 0xFF); /* right */
526       _kernel_oswrch((((this->screen->w-1) << this->hidden->xeig) >> 8) & 0xFF);
527       _kernel_oswrch(((this->screen->h-1) << this->hidden->yeig) & 0xFF); /* top */
528       _kernel_oswrch((((this->screen->h-1) << this->hidden->yeig) >> 8) & 0xFF);
529    }
530 }
531
532
533 int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
534 {
535         _kernel_swi_regs regs;
536         int palette[256];
537
538         regs.r[0] = -1;
539         regs.r[1] = -1;
540         regs.r[2] = (int)palette;
541         regs.r[3] = 1024;
542         regs.r[4] = 0;
543         _kernel_swi(ColourTrans_ReadPalette, &regs, &regs);
544
545         while(ncolors--)
546         {
547                 palette[firstcolor] = ((colors->b) << 24) | ((colors->g) << 16) | ((colors->r) << 8);
548                 firstcolor++;
549                 colors++;
550         }
551
552         regs.r[0] = -1;
553         regs.r[1] = -1;
554         regs.r[2] = (int)palette;
555         regs.r[3] = 0;
556         regs.r[4] = 0;
557         _kernel_swi(ColourTrans_WritePalette, &regs, &regs);
558
559         return(1);
560 }
561
562
563 static int cmpmodes(const void *va, const void *vb)
564 {
565     SDL_Rect *a = *(SDL_Rect **)va;
566     SDL_Rect *b = *(SDL_Rect **)vb;
567     if(a->w == b->w)
568         return b->h - a->h;
569     else
570         return b->w - a->w;
571 }
572
573 static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h)
574 {
575         SDL_Rect *mode;
576         int i, index;
577         int next_mode;
578
579         /* Check to see if we already have this mode */
580         if ( bpp < 8 ) {  /* Not supported */
581                 return(0);
582         }
583         index = ((bpp+7)/8)-1;
584         for ( i=0; i<SDL_nummodes[index]; ++i ) {
585                 mode = SDL_modelist[index][i];
586                 if ( (mode->w == w) && (mode->h == h) ) {
587                         return(0);
588                 }
589         }
590
591         /* Set up the new video mode rectangle */
592         mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
593         if ( mode == NULL ) {
594                 SDL_OutOfMemory();
595                 return(-1);
596         }
597         mode->x = 0;
598         mode->y = 0;
599         mode->w = w;
600         mode->h = h;
601
602         /* Allocate the new list of modes, and fill in the new mode */
603         next_mode = SDL_nummodes[index];
604         SDL_modelist[index] = (SDL_Rect **)
605                SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
606         if ( SDL_modelist[index] == NULL ) {
607                 SDL_OutOfMemory();
608                 SDL_nummodes[index] = 0;
609                 SDL_free(mode);
610                 return(-1);
611         }
612         SDL_modelist[index][next_mode] = mode;
613         SDL_modelist[index][next_mode+1] = NULL;
614         SDL_nummodes[index]++;
615
616         return(0);
617 }
618
619 void FULLSCREEN_SetWriteBank(int bank)
620 {
621    _kernel_swi_regs regs;
622    regs.r[0] = 112;
623    regs.r[1] = bank+1;
624    _kernel_swi(OS_Byte, &regs, &regs);
625 }
626
627 void FULLSCREEN_SetDisplayBank(int bank)
628 {
629    _kernel_swi_regs regs;
630    regs.r[0] = 113;
631    regs.r[1] = bank+1;
632    _kernel_swi(OS_Byte, &regs, &regs);
633 }
634
635
636 /** Disable special escape key processing */
637 static void FULLSCREEN_DisableEscape()
638 {
639    _kernel_swi_regs regs;
640    regs.r[0] = 229;
641    regs.r[1] = 1;
642    regs.r[2] = 0;
643    _kernel_swi(OS_Byte, &regs, &regs);
644   
645 }
646
647 /** Enable special escape key processing */
648 static void FULLSCREEN_EnableEscape()
649 {
650    _kernel_swi_regs regs;
651    regs.r[0] = 229;
652    regs.r[1] = 0;
653    regs.r[2] = 0;
654    _kernel_swi(OS_Byte, &regs, &regs);
655   
656 }
657
658 /** Store caption in case this is called before we create a window */
659 void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon)
660 {
661         SDL_strlcpy(this->hidden->title, title, SDL_arraysize(this->hidden->title));
662 }
663
664 /* Set screen mode
665 *
666 *  Returns 1 if mode is set ok, otherwise 0
667 */
668
669 int FULLSCREEN_SetMode(int width, int height, int bpp)
670 {
671    SCREENMODEBLOCK smb;
672    _kernel_swi_regs regs;
673
674    smb.flags = 1;
675    smb.x_pixels = width;
676    smb.y_pixels = height;
677    smb.mode_vars[0] = -1;
678
679    switch(bpp)
680    {
681         case 8:
682                 smb.pixel_depth = 3;
683                 /* Note: Need to set ModeFlags to 128 and NColour variables to 255 get full 8 bit palette */
684                 smb.mode_vars[0] = 0; smb.mode_vars[1] = 128; /* Mode flags */
685                 smb.mode_vars[2] = 3; smb.mode_vars[3] = 255; /* NColour (number of colours -1) */
686                 smb.mode_vars[4] = -1; /* End of list */
687                 break;
688
689         case 15:
690         case 16:
691                 smb.pixel_depth = 4;
692                 break;
693
694         case 32:
695                 smb.pixel_depth = 5;
696                 break;
697
698         default:
699                 SDL_SetError("Pixel depth not supported");
700                 return 0;
701                 break;
702    }
703    
704    smb.frame_rate = -1;
705
706    regs.r[0] = 0;
707    regs.r[1] = (int)&smb;
708
709    if (_kernel_swi(OS_ScreenMode, &regs, &regs) != 0)
710    {
711            SDL_SetError("Couldn't set requested mode");
712            return 0;
713    }
714
715     /* Turn cursor off*/
716     _kernel_oswrch(23);_kernel_oswrch(1);_kernel_oswrch(0);
717     _kernel_oswrch(0);_kernel_oswrch(0);_kernel_oswrch(0);
718     _kernel_oswrch(0);_kernel_oswrch(0);_kernel_oswrch(0);
719     _kernel_oswrch(0);_kernel_oswrch(0);
720
721    return 1;
722 }
723
724 /* Get Start addresses for the screen banks */
725 void FULLSCREEN_SetupBanks(_THIS)
726 {
727    _kernel_swi_regs regs;
728    int block[5];
729    block[0] = 148; /* Write screen start */
730    block[1] = 149; /* Display screen start */
731    block[2] = 4;  /* X eig factor */
732    block[3] = 5;  /* Y eig factor */
733    block[4] = -1;  /* End of list of variables to request */
734
735    regs.r[0] = (int)block;
736    regs.r[1] = (int)block;
737    _kernel_swi(OS_ReadVduVariables, &regs, &regs);
738
739    this->hidden->bank[0] = (void *)block[0];
740    this->hidden->bank[1] = (void *)block[1];
741    this->hidden->xeig = block[2];
742    this->hidden->yeig = block[3];
743 }
744
745 /* Toggle to full screen mode from the WIMP */
746
747 int FULLSCREEN_ToggleFromWimp(_THIS)
748 {
749    int width = this->screen->w;
750    int height = this->screen->h;
751    int bpp = this->screen->format->BitsPerPixel;
752
753    RISCOS_StoreWimpMode();
754    if (FULLSCREEN_SetMode(width, height, bpp))
755    {
756        char *buffer = this->hidden->alloc_bank; /* This is start of sprite data */
757        /* Support back buffer mode only */
758        if (riscos_backbuffer == 0) riscos_backbuffer = 1;
759
760        FULLSCREEN_SetupBanks(this);
761
762        this->hidden->bank[0] = buffer + 60; /* Start of sprite data */
763        if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
764
765            this->hidden->current_bank = 0;
766            this->screen->pixels = this->hidden->bank[0];
767
768        /* Copy back buffer to screen memory */
769        SDL_memcpy(this->hidden->bank[1], this->hidden->bank[0], width * height * this->screen->format->BytesPerPixel);
770
771        FULLSCREEN_SetDeviceMode(this);
772        return 1;
773    } else
774       RISCOS_RestoreWimpMode();
775
776    return 0;
777 }