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/os.h"
45#include "unixlib/local.h"
46
47/* Private structures */
48typedef 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 */
60void FULLSCREEN_SetDeviceMode(_THIS);
61int FULLSCREEN_SetMode(int width, int height, int bpp);
62void FULLSCREEN_SetupBanks(_THIS);
63
64/* SDL video device functions for fullscreen mode */
65static int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
66static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface);
67void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon);
68extern int RISCOS_GetWmInfo(_THIS, SDL_SysWMinfo *info);
69
70/* UpdateRects variants */
71static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
72static void FULLSCREEN_UpdateRectsMemCpy(_THIS, int numrects, SDL_Rect *rects);
73static void FULLSCREEN_UpdateRects8bpp(_THIS, int numrects, SDL_Rect *rects);
74static void FULLSCREEN_UpdateRects16bpp(_THIS, int numrects, SDL_Rect *rects);
75static void FULLSCREEN_UpdateRects32bpp(_THIS, int numrects, SDL_Rect *rects);
76static void FULLSCREEN_UpdateRectsOS(_THIS, int numrects, SDL_Rect *rects);
77
78/* Local helper functions */
79static int cmpmodes(const void *va, const void *vb);
80static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h);
81void FULLSCREEN_SetWriteBank(int bank);
82void FULLSCREEN_SetDisplayBank(int bank);
83static void FULLSCREEN_DisableEscape();
84static void FULLSCREEN_EnableEscape();
85void FULLSCREEN_BuildModeList(_THIS);
86
87/* Following variable is set up in riskosTask.c */
88extern 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 */
91extern unsigned char *WIMP_CreateBuffer(int width, int height, int bpp);
92
93/* Fast assembler copy */
94extern void RISCOS_Put32(void *to, int pixels, int pitch, int rows, void *from, int src_skip_bytes);
95
96SDL_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 */
240void 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 */
293void 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
360static 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 */
377static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
378{
379}
380
381/* Safe but slower Memory copy from our allocated back buffer */
382static 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. */
405static 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. */
435static 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 */
463static 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. */
484static 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
533int 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
563static 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
573static 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
619void 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
627void 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 */
637static 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 */
648static 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 */
659void 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
669int 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 */
725void 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
747int 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