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