Home | History | Annotate | Download | only in riscos
      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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /*
     25      File added by Alan Buckley (alan_baa (at) 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 }
    778