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