src/video/riscos/SDL_riscosFullScreenVideo.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 05 Nov 2003 23:11:05 +0000
changeset 733 9557ac1857a3
parent 630 550bccdf04bd
child 769 b8d311d90021
permissions -rw-r--r--
Date: Mon, 13 Oct 2003 13:37:18 +0100
From: "alan buckley"
Subject: Modification for RISC OS SDL port (SDL_riscosevents.c)

This modification improves the key press to Unicode character translation.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  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@devolution.com
    21 */
    22 
    23 /*
    24      File added by Alan Buckley (alan_baa@hotmail.com) for RISCOS compatability
    25 	 27 March 2003
    26 
    27      Implements RISCOS full screen display.
    28 */
    29 
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 
    34 #include "SDL.h"
    35 #include "SDL_error.h"
    36 #include "SDL_video.h"
    37 #include "SDL_mouse.h"
    38 #include "SDL_sysvideo.h"
    39 #include "SDL_pixels_c.h"
    40 #include "SDL_events_c.h"
    41 
    42 #include "SDL_riscostask.h"
    43 #include "SDL_riscosvideo.h"
    44 #include "SDL_riscosevents_c.h"
    45 #include "SDL_riscosmouse_c.h"
    46 
    47 #include "kernel.h"
    48 #include "swis.h"
    49 #include "unixlib/os.h"
    50 #include "unixlib/local.h"
    51 
    52 /* Private structures */
    53 typedef struct tagScreenModeBlock
    54 {
    55    int flags;  // mode selector flags, bit 0 = 1, bit 1-7 format specifier, 8-31 reserved
    56    int x_pixels;
    57    int y_pixels;
    58    int pixel_depth;  // 2^pixel_depth = bpp,i.e. 0 = 1, 1 = 2, 4 = 16, 5 = 32
    59    int frame_rate;   // -1 use first match
    60    int mode_vars[5]; // array of index, value pairs terminated by -1
    61 } SCREENMODEBLOCK;
    62 
    63 
    64 /* Helper functions */
    65 void FULLSCREEN_SetDeviceMode(_THIS);
    66 int FULLSCREEN_SetMode(int width, int height, int bpp);
    67 void FULLSCREEN_SetupBanks(_THIS);
    68 
    69 /* SDL video device functions for fullscreen mode */
    70 static int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
    71 static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface);
    72 static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
    73 void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon);
    74 extern int RISCOS_GetWmInfo(_THIS, SDL_SysWMinfo *info);
    75 
    76 /* Local helper functions */
    77 static int cmpmodes(const void *va, const void *vb);
    78 static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h);
    79 void FULLSCREEN_SetWriteBank(int bank);
    80 void FULLSCREEN_SetDisplayBank(int bank);
    81 static void FULLSCREEN_DisableEscape();
    82 static void FULLSCREEN_EnableEscape();
    83 void FULLSCREEN_BuildModeList(_THIS);
    84 
    85 /* Following variable is set up in riskosTask.c */
    86 extern int riscos_backbuffer; /* Create a back buffer in system memory for full screen mode */
    87 
    88 
    89 
    90 SDL_Surface *FULLSCREEN_SetVideoMode(_THIS, SDL_Surface *current,
    91 				int width, int height, int bpp, Uint32 flags)
    92 {
    93    _kernel_swi_regs regs;
    94    Uint32 Rmask = 0;
    95    Uint32 Gmask = 0;
    96    Uint32 Bmask = 0;
    97    int create_back_buffer = riscos_backbuffer;
    98 
    99    switch(bpp)
   100    {
   101 	case 8:
   102 		flags |= SDL_HWPALETTE;
   103 		break;
   104 
   105 	case 15:
   106 	case 16:
   107 		Bmask = 0x00007c00;
   108 		Gmask = 0x000003e0;
   109 		Rmask = 0x0000001f;
   110 		break;
   111 
   112 	case 32:
   113 		Bmask = 0x00ff0000;
   114 		Gmask = 0x0000ff00;
   115 		Rmask = 0x000000ff;
   116 		break;
   117 
   118 	default:
   119 		SDL_SetError("Pixel depth not supported");
   120 		return NULL;
   121 		break;
   122    }
   123 
   124    if (FULLSCREEN_SetMode(width, height, bpp) == 0)
   125    {
   126 	   SDL_SetError("Couldn't set requested mode");
   127 	   return (NULL);
   128    }
   129 
   130 /* 	printf("Setting mode %dx%d\n", width, height); */
   131 
   132 	/* Allocate the new pixel format for the screen */
   133 	if ( ! SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0) ) {
   134 	    RISCOS_RestoreWimpMode();
   135 		SDL_SetError("Couldn't allocate new pixel format for requested mode");
   136 		return(NULL);
   137 	}
   138 
   139 	/* Set up the new mode framebuffer */
   140 	current->w = width;
   141 	this->hidden->height = current->h = height;
   142 
   143    regs.r[0] = -1; /* -1 for current screen mode */
   144 
   145    /* Get screen width in bytes */
   146    regs.r[1] = 6; // Screen Width in bytes
   147    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
   148 
   149    current->pitch = regs.r[2];
   150 
   151    if (flags & SDL_DOUBLEBUF)
   152    {
   153 	   regs.r[0] = 2; /* Screen area */
   154 	   _kernel_swi(OS_ReadDynamicArea, &regs, &regs);
   155 	   
   156 	   /* Reg 1 has amount of memory currently used for display */
   157 	   regs.r[0] = 2; /* Screen area */
   158 	   regs.r[1] = (current->pitch * height * 2) - regs.r[1];
   159 	   if (_kernel_swi(OS_ChangeDynamicArea, &regs, &regs) != NULL)
   160 	   {
   161 		   /* Can't allocate enough screen memory for double buffer */
   162 		   flags &= ~SDL_DOUBLEBUF;
   163 	   }
   164    }
   165    
   166   	current->flags = flags | SDL_FULLSCREEN | SDL_HWSURFACE | SDL_PREALLOC;
   167 	
   168 
   169 	/* Need to set display banks here for double buffering */
   170 	if (flags & SDL_DOUBLEBUF)
   171 	{
   172 	   FULLSCREEN_SetWriteBank(0);
   173 	   FULLSCREEN_SetDisplayBank(1);
   174 
   175          create_back_buffer = 0; /* Don't need a back buffer for a double buffered display */
   176     }
   177 
   178     FULLSCREEN_SetupBanks(this);
   179 
   180     if (create_back_buffer)
   181     {
   182        /* If not double buffered we may need to create a memory
   183        ** back buffer to simulate processing on other OS's. 
   184          ** This is turned on by setting the enviromental variable
   185          ** SDL$<name>$BackBuffer to 1
   186          */    
   187        this->hidden->bank[0] = malloc(height * current->pitch);
   188        if (this->hidden->bank[0] == 0)
   189        {
   190  	       RISCOS_RestoreWimpMode();
   191            SDL_SetError("Couldnt allocate memory for back buffer");
   192            return (NULL);
   193        }
   194        /* Surface updated in programs is now a software surface */
   195        current->flags &= ~SDL_HWSURFACE;
   196     }
   197 
   198 	   /* Store address of allocated screen bank to be freed later */
   199 	   if (this->hidden->alloc_bank) free(this->hidden->alloc_bank);
   200 	   if (create_back_buffer)
   201 	   {
   202 		   this->hidden->alloc_bank = this->hidden->bank[0];
   203 	   } else
   204 		   this->hidden->alloc_bank = 0;
   205 
   206        // Clear both banks to black
   207        memset(this->hidden->bank[0], 0, height * current->pitch);
   208 	   memset(this->hidden->bank[1], 0, height * current->pitch);
   209 
   210  	   this->hidden->current_bank = 0;
   211 	   current->pixels = this->hidden->bank[0];
   212 
   213 	/* Reset device functions for the wimp */
   214 	FULLSCREEN_SetDeviceMode(this);
   215 
   216 /*	FULLSCREEN_DisableEscape(); */
   217 
   218 	/* We're done */
   219 	return(current);
   220 }
   221 
   222 /* Reset any device functions that have been changed because we have run in WIMP mode */
   223 void FULLSCREEN_SetDeviceMode(_THIS)
   224 {
   225 	if (this->SetColors == FULLSCREEN_SetColors) return; /* Already set up */
   226 
   227 	this->SetColors   = FULLSCREEN_SetColors;
   228 	this->UpdateRects = FULLSCREEN_UpdateRects;
   229 
   230 	this->FlipHWSurface = FULLSCREEN_FlipHWSurface;
   231 
   232 	this->SetCaption = FULLSCREEN_SetWMCaption;
   233 	this->SetIcon = NULL;
   234 	this->IconifyWindow = NULL;
   235 	
   236 	this->ShowWMCursor = RISCOS_ShowWMCursor;
   237 	this->WarpWMCursor = FULLSCREEN_WarpWMCursor;
   238 
   239 	this->PumpEvents = FULLSCREEN_PumpEvents;	
   240 }
   241 
   242 /* Query for the list of available video modes */
   243 void FULLSCREEN_BuildModeList(_THIS)
   244 {
   245 	_kernel_swi_regs regs;
   246 	char *enumInfo = NULL;
   247 	char *enum_ptr;
   248 	int *blockInfo;
   249 	int j;
   250 	int num_modes;
   251 
   252 	/* Find out how much space we need */
   253 	regs.r[0] = 2; /* Reason code */
   254 	regs.r[2] = 0; /* Number of modes to skip */
   255 	regs.r[6] = 0; /* pointer to block or 0 for count */
   256 	regs.r[7] = 0; /* Size of block in bytes */
   257 	_kernel_swi(OS_ScreenMode, &regs, &regs);
   258 
   259     num_modes = -regs.r[2];
   260 
   261 	/* Video memory should be in r[5] */
   262 	this->info.video_mem = regs.r[5]/1024;
   263 
   264 	enumInfo = (unsigned char *)malloc(-regs.r[7]);
   265 	if (enumInfo == NULL)
   266 	{
   267 		SDL_OutOfMemory();
   268 		return;
   269 	}
   270 	/* Read mode information into block */
   271 	regs.r[2] = 0;
   272 	regs.r[6] = (int)enumInfo;
   273 	regs.r[7] = -regs.r[7];
   274 	_kernel_swi(OS_ScreenMode, &regs, &regs);
   275 
   276 	enum_ptr = enumInfo;
   277 
   278 	for (j =0; j < num_modes;j++)
   279 	{
   280 		blockInfo = (int *)enum_ptr;
   281 		if ((blockInfo[1] & 255) == 1) /* We understand this format */
   282 		{
   283 			switch(blockInfo[4])
   284 			{
   285 			case 3: /* 8 bits per pixel */
   286 				FULLSCREEN_AddMode(this, 8, blockInfo[2], blockInfo[3]);
   287 				break;
   288 			case 4: /* 15 bits per pixel */
   289 				FULLSCREEN_AddMode(this, 15, blockInfo[2], blockInfo[3]);
   290 				break;
   291 			case 5: /* 32 bits per pixel */
   292 				FULLSCREEN_AddMode(this, 32, blockInfo[2], blockInfo[3]);
   293 				break;
   294 			}
   295 		}
   296 
   297 		enum_ptr += blockInfo[0];
   298 	}
   299 
   300 	free(enumInfo);
   301 		
   302 	/* Sort the mode lists */
   303 	for ( j=0; j<NUM_MODELISTS; ++j ) {
   304 		if ( SDL_nummodes[j] > 0 ) {
   305 			qsort(SDL_modelist[j], SDL_nummodes[j], sizeof *SDL_modelist[j], cmpmodes);
   306 		}
   307 	}
   308 }
   309 
   310 static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface)
   311 {
   312    _kernel_swi_regs regs;
   313    regs.r[0] = 19;
   314    /* Wait for Vsync */
   315    _kernel_swi(OS_Byte, &regs, &regs);
   316 
   317    FULLSCREEN_SetDisplayBank(this->hidden->current_bank);
   318    this->hidden->current_bank ^= 1;
   319    FULLSCREEN_SetWriteBank(this->hidden->current_bank);
   320    surface->pixels = this->hidden->bank[this->hidden->current_bank];
   321 
   322 	return(0);
   323 }
   324 
   325 static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
   326 {
   327    if (riscos_backbuffer && (this->screen->flags & SDL_DOUBLEBUF) == 0)
   328    {
   329       /* If not double buffered copy rectangles to main screen now */
   330       int j;
   331       char *to, *from;
   332       int pitch = this->screen->pitch;
   333       int row;
   334       int xmult = this->screen->format->BytesPerPixel;
   335       for (j = 0; j < numrects; j++)
   336       {
   337          from = this->hidden->bank[0] + rects->x * xmult + rects->y * pitch;
   338          to  = this->hidden->bank[1] + rects->x * xmult + rects->y * pitch;
   339          for (row = 0; row < rects->h; row++)
   340          {
   341              memcpy(to, from, rects->w * xmult);
   342              from += pitch;
   343              to += pitch;
   344          }
   345          rects++;
   346       }
   347    }
   348 }
   349 
   350 int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
   351 {
   352 	_kernel_swi_regs regs;
   353 	int palette[256];
   354 
   355 	regs.r[0] = -1;
   356 	regs.r[1] = -1;
   357 	regs.r[2] = (int)palette;
   358 	regs.r[3] = 1024;
   359 	regs.r[4] = 0;
   360 	_kernel_swi(ColourTrans_ReadPalette, &regs, &regs);
   361 
   362 	while(ncolors--)
   363 	{
   364 		palette[firstcolor] = ((colors->b) << 24) | ((colors->g) << 16) | ((colors->r) << 8);
   365 		firstcolor++;
   366 		colors++;
   367 	}
   368 
   369 	regs.r[0] = -1;
   370 	regs.r[1] = -1;
   371 	regs.r[2] = (int)palette;
   372 	regs.r[3] = 0;
   373 	regs.r[4] = 0;
   374 	_kernel_swi(ColourTrans_WritePalette, &regs, &regs);
   375 
   376 	return(1);
   377 }
   378 
   379 
   380 static int cmpmodes(const void *va, const void *vb)
   381 {
   382     SDL_Rect *a = *(SDL_Rect **)va;
   383     SDL_Rect *b = *(SDL_Rect **)vb;
   384     if(a->w > b->w)
   385         return -1;
   386     return b->h - a->h;
   387 }
   388 
   389 static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h)
   390 {
   391 	SDL_Rect *mode;
   392 	int i, index;
   393 	int next_mode;
   394 
   395 	/* Check to see if we already have this mode */
   396 	if ( bpp < 8 ) {  /* Not supported */
   397 		return(0);
   398 	}
   399 	index = ((bpp+7)/8)-1;
   400 	for ( i=0; i<SDL_nummodes[index]; ++i ) {
   401 		mode = SDL_modelist[index][i];
   402 		if ( (mode->w == w) && (mode->h == h) ) {
   403 			return(0);
   404 		}
   405 	}
   406 
   407 	/* Set up the new video mode rectangle */
   408 	mode = (SDL_Rect *)malloc(sizeof *mode);
   409 	if ( mode == NULL ) {
   410 		SDL_OutOfMemory();
   411 		return(-1);
   412 	}
   413 	mode->x = 0;
   414 	mode->y = 0;
   415 	mode->w = w;
   416 	mode->h = h;
   417 
   418 	/* Allocate the new list of modes, and fill in the new mode */
   419 	next_mode = SDL_nummodes[index];
   420 	SDL_modelist[index] = (SDL_Rect **)
   421 	       realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
   422 	if ( SDL_modelist[index] == NULL ) {
   423 		SDL_OutOfMemory();
   424 		SDL_nummodes[index] = 0;
   425 		free(mode);
   426 		return(-1);
   427 	}
   428 	SDL_modelist[index][next_mode] = mode;
   429 	SDL_modelist[index][next_mode+1] = NULL;
   430 	SDL_nummodes[index]++;
   431 
   432 	return(0);
   433 }
   434 
   435 void FULLSCREEN_SetWriteBank(int bank)
   436 {
   437    _kernel_swi_regs regs;
   438    regs.r[0] = 112;
   439    regs.r[1] = bank+1;
   440    _kernel_swi(OS_Byte, &regs, &regs);
   441 }
   442 
   443 void FULLSCREEN_SetDisplayBank(int bank)
   444 {
   445    _kernel_swi_regs regs;
   446    regs.r[0] = 113;
   447    regs.r[1] = bank+1;
   448    _kernel_swi(OS_Byte, &regs, &regs);
   449 }
   450 
   451 
   452 /** Disable special escape key processing */
   453 static void FULLSCREEN_DisableEscape()
   454 {
   455    _kernel_swi_regs regs;
   456    regs.r[0] = 229;
   457    regs.r[1] = 1;
   458    regs.r[2] = 0;
   459    _kernel_swi(OS_Byte, &regs, &regs);
   460   
   461 }
   462 
   463 /** Enable special escape key processing */
   464 static void FULLSCREEN_EnableEscape()
   465 {
   466    _kernel_swi_regs regs;
   467    regs.r[0] = 229;
   468    regs.r[1] = 0;
   469    regs.r[2] = 0;
   470    _kernel_swi(OS_Byte, &regs, &regs);
   471   
   472 }
   473 
   474 /** Store caption in case this is called before we create a window */
   475 void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon)
   476 {
   477 	strncpy(this->hidden->title, title, 255);
   478 	this->hidden->title[255] = 0;
   479 }
   480 
   481 /* Set screen mode
   482 *
   483 *  Returns 1 if mode is set ok, otherwise 0
   484 */
   485 
   486 int FULLSCREEN_SetMode(int width, int height, int bpp)
   487 {
   488    SCREENMODEBLOCK smb;
   489    _kernel_swi_regs regs;
   490 
   491    smb.flags = 1;
   492    smb.x_pixels = width;
   493    smb.y_pixels = height;
   494    smb.mode_vars[0] = -1;
   495 
   496    switch(bpp)
   497    {
   498 	case 8:
   499 		smb.pixel_depth = 3;
   500 		/* Note: Need to set ModeFlags to 128 and NColour variables to 255 get full 8 bit palette */
   501 		smb.mode_vars[0] = 0; smb.mode_vars[1] = 128; /* Mode flags */
   502 		smb.mode_vars[2] = 3; smb.mode_vars[3] = 255; /* NColour (number of colours -1) */
   503 		smb.mode_vars[4] = -1; /* End of list */
   504 		break;
   505 
   506 	case 15:
   507 	case 16:
   508 		smb.pixel_depth = 4;
   509 		break;
   510 
   511 	case 32:
   512 		smb.pixel_depth = 5;
   513 		break;
   514 
   515 	default:
   516 		SDL_SetError("Pixel depth not supported");
   517 		return 0;
   518 		break;
   519    }
   520    
   521    smb.frame_rate = -1;
   522 
   523    regs.r[0] = 0;
   524    regs.r[1] = (int)&smb;
   525 
   526    if (_kernel_swi(OS_ScreenMode, &regs, &regs) != 0)
   527    {
   528 	   SDL_SetError("Couldn't set requested mode");
   529 	   return 0;
   530    }
   531 
   532     /* Turn cursor off*/
   533     _kernel_oswrch(23);_kernel_oswrch(1);_kernel_oswrch(0);
   534     _kernel_oswrch(0);_kernel_oswrch(0);_kernel_oswrch(0);
   535     _kernel_oswrch(0);_kernel_oswrch(0);_kernel_oswrch(0);
   536     _kernel_oswrch(0);_kernel_oswrch(0);
   537 
   538    return 1;
   539 }
   540 
   541 /* Get Start addresses for the screen banks */
   542 void FULLSCREEN_SetupBanks(_THIS)
   543 {
   544    _kernel_swi_regs regs;
   545    int block[5];
   546    block[0] = 148; /* Write screen start */
   547    block[1] = 149; /* Display screen start */
   548    block[2] = 4;  /* X eig factor */
   549    block[3] = 5;  /* Y eig factor */
   550    block[4] = -1;  /* End of list of variables to request */
   551 
   552    regs.r[0] = (int)block;
   553    regs.r[1] = (int)block;
   554    _kernel_swi(OS_ReadVduVariables, &regs, &regs);
   555 
   556    this->hidden->bank[0] = (void *)block[0];
   557    this->hidden->bank[1] = (void *)block[1];
   558    this->hidden->xeig = block[2];
   559    this->hidden->yeig = block[3];
   560 }
   561 
   562 /* Toggle to full screen mode from the WIMP */
   563 
   564 int FULLSCREEN_ToggleFromWimp(_THIS)
   565 {
   566    int width = this->screen->w;
   567    int height = this->screen->h;
   568    int bpp = this->screen->format->BitsPerPixel;
   569 
   570    RISCOS_StoreWimpMode();
   571    if (FULLSCREEN_SetMode(width, height, bpp))
   572    {
   573        char *buffer = this->hidden->alloc_bank; /* This is start of sprite data */
   574        /* Support back buffer mode only */
   575        riscos_backbuffer = 1;
   576 
   577        FULLSCREEN_SetupBanks(this);
   578 
   579        this->hidden->bank[0] = buffer + 60; /* Start of sprite data */
   580        if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
   581 
   582 	   this->hidden->current_bank = 0;
   583 	   this->screen->pixels = this->hidden->bank[0];
   584 
   585        /* Copy back buffer to screen memory */
   586        memcpy(this->hidden->bank[1], this->hidden->bank[0], width * height * this->screen->format->BytesPerPixel);
   587 
   588        FULLSCREEN_SetDeviceMode(this);
   589        return 1;
   590    } else
   591       RISCOS_RestoreWimpMode();
   592 
   593    return 0;
   594 }