Home | History | Annotate | Download | only in riscos
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2004 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public
     16     License along with this library; if not, write to the Free
     17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 
     19     Sam Lantinga
     20     slouken (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 Wimp 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 
     45 /* Initialization/Query functions */
     46 SDL_Rect **WIMP_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
     47 SDL_Surface *WIMP_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
     48 int WIMP_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
     49 void WIMP_SetWMCaption(_THIS, const char *title, const char *icon);
     50 
     51 
     52 extern unsigned char *WIMP_CreateBuffer(int width, int height, int bpp);
     53 extern void WIMP_PumpEvents(_THIS);
     54 extern void WIMP_PlotSprite(_THIS, int x, int y);
     55 extern void WIMP_SetupPlotInfo(_THIS);
     56 extern void WIMP_SetFocus(int win);
     57 
     58 /* etc. */
     59 static void WIMP_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
     60 
     61 /* RISC OS Wimp handling helpers */
     62 void WIMP_ReadModeInfo(_THIS);
     63 unsigned int WIMP_SetupWindow(_THIS, SDL_Surface *surface);
     64 void WIMP_SetDeviceMode(_THIS);
     65 void WIMP_DeleteWindow(_THIS);
     66 
     67 /* FULLSCREEN function required for wimp/fullscreen toggling */
     68 extern int FULLSCREEN_SetMode(int width, int height, int bpp);
     69 
     70 /* Currently need to set this up here as it only works if you
     71    start up in a Wimp mode */
     72 extern int RISCOS_ToggleFullScreen(_THIS, int fullscreen);
     73 
     74 extern int riscos_backbuffer;
     75 extern int mouseInWindow;
     76 extern int riscos_closeaction;
     77 
     78 /* Following needed to ensure window is shown immediately */
     79 extern int hasFocus;
     80 extern void WIMP_Poll(_THIS, int waitTime);
     81 
     82 SDL_Surface *WIMP_SetVideoMode(_THIS, SDL_Surface *current,
     83 				int width, int height, int bpp, Uint32 flags)
     84 {
     85    Uint32 Rmask = 0;
     86    Uint32 Gmask = 0;
     87    Uint32 Bmask = 0;
     88    char *buffer = NULL;
     89    int bytesPerPixel = 1;
     90 
     91    /* Don't support double buffering in Wimp mode */
     92    flags &= ~SDL_DOUBLEBUF;
     93    flags &= ~SDL_HWSURFACE;
     94 
     95    switch(bpp)
     96    {
     97 	case 8:
     98 		/* Emulated palette using ColourTrans */
     99 		flags |= SDL_HWPALETTE;
    100 		break;
    101 
    102 	case 15:
    103 	case 16:
    104 		Bmask = 0x00007c00;
    105 		Gmask = 0x000003e0;
    106 		Rmask = 0x0000001f;
    107 		bytesPerPixel = 2;
    108 		break;
    109 
    110 	case 32:
    111 		Bmask = 0x00ff0000;
    112 		Gmask = 0x0000ff00;
    113 		Rmask = 0x000000ff;
    114 		bytesPerPixel = 4;
    115 		break;
    116 
    117 	default:
    118 		SDL_SetError("Pixel depth not supported");
    119 		return NULL;
    120 		break;
    121    }
    122 
    123 /* 	printf("Setting mode %dx%d\n", width, height);*/
    124 
    125 	/* Allocate the new pixel format for the screen */
    126 	if ( ! SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0) ) {
    127 		SDL_SetError("Couldn't allocate new pixel format for requested mode");
    128 		return(NULL);
    129 	}
    130 
    131 	/* Set up the new mode framebuffer */
    132 	current->w = width;
    133 	this->hidden->height = current->h = height;
    134 
    135 	if (bpp == 15) bpp = 16;
    136 	buffer = WIMP_CreateBuffer(width, height, bpp);
    137 	if (buffer == NULL)
    138 	{
    139 		SDL_SetError("Couldn't create sprite for video memory");
    140 		return (NULL);
    141 	}
    142 
    143 	this->hidden->bank[0] = buffer + 60; /* Start of sprite data */
    144 	if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
    145 
    146 	this->hidden->bank[1] = buffer;      /* Start of buffer */
    147 
    148 	/* Remember sprite buffer so it can be freed later */
    149 	if (this->hidden->alloc_bank) SDL_free(this->hidden->alloc_bank);
    150 	this->hidden->alloc_bank = buffer;
    151 
    152 	current->pitch = width * bytesPerPixel;
    153 	if ((current->pitch & 3))
    154 	{
    155 		/* Sprites are 32bit word aligned */
    156 		current->pitch += (4 - (current->pitch & 3));
    157 	}
    158 
    159   	current->flags = flags | SDL_PREALLOC;
    160 
    161 	WIMP_ReadModeInfo(this);
    162 
    163     SDL_memset(this->hidden->bank[0], 0, height * current->pitch);
    164 
    165 	this->hidden->current_bank = 0;
    166 	current->pixels = this->hidden->bank[0];
    167 
    168 
    169 	if (WIMP_SetupWindow(this, current) == 0)
    170 	{
    171 		SDL_SetError("Unable to create window to display surface");
    172 		return NULL;
    173 	}
    174 
    175 	/* Reset device functions for the wimp */
    176 	WIMP_SetDeviceMode(this);
    177 
    178 	/* Needs to set up plot info after window has been created */
    179 	/* Not sure why, but plots don't work if I do it earlier */
    180 	WIMP_SetupPlotInfo(this);
    181 
    182 	/* Poll until window is shown */
    183 	{
    184 	   /* We wait until it gets the focus, but give up after 5 seconds
    185 	      in case the focus is prevented in any way.
    186 	   */
    187 	   Uint32 now = SDL_GetTicks();
    188 	   while (!hasFocus && SDL_GetTicks() - now < 5000)
    189 	   {
    190 	      WIMP_Poll(this, 0);
    191 	   }
    192 	}
    193 
    194 	/* We're done */
    195 	return(current);
    196 }
    197 
    198 
    199 void WIMP_ReadModeInfo(_THIS)
    200 {
    201 	_kernel_swi_regs regs;
    202 	int vars[6];
    203 	int vals[5];
    204 
    205 	vars[0] = 4;  /* XEig */
    206 	vars[1] = 5;  /* YEig */
    207 	vars[2] = 9;  /* Log base 2 bpp */
    208 	vars[3] = 11; /* Screen Width - 1 */
    209 	vars[4] = 12; /* Screen Depth - 1 */
    210 	vars[5] = -1; /* Terminate list */
    211 
    212 	regs.r[0] = (int)vars;
    213 	regs.r[1] = (int)vals;
    214 	_kernel_swi(OS_ReadVduVariables, &regs, &regs);
    215 	this->hidden->xeig = vals[0];
    216 	this->hidden->yeig = vals[1];
    217 	this->hidden->screen_bpp = 1 << vals[2];
    218 	this->hidden->screen_width = vals[3] + 1;
    219 	this->hidden->screen_height = vals[4] + 1;
    220 }
    221 
    222 /* Set device function to call the correct versions for running
    223    in a wimp window */
    224 
    225 void WIMP_SetDeviceMode(_THIS)
    226 {
    227 	if (this->UpdateRects == WIMP_UpdateRects) return; /* Already set up */
    228 
    229 	this->SetColors   = WIMP_SetColors;
    230 	this->UpdateRects = WIMP_UpdateRects;
    231 
    232 	this->FlipHWSurface = NULL;
    233 
    234 	this->SetCaption = WIMP_SetWMCaption;
    235 	this->SetIcon = NULL;
    236 	this->IconifyWindow = NULL;
    237 
    238 	this->ShowWMCursor = WIMP_ShowWMCursor;
    239 	this->WarpWMCursor = WIMP_WarpWMCursor;
    240 
    241         this->ToggleFullScreen = RISCOS_ToggleFullScreen;
    242 
    243 	this->PumpEvents = WIMP_PumpEvents;
    244 }
    245 
    246 /* Setup the Window to display the surface */
    247 unsigned int WIMP_SetupWindow(_THIS, SDL_Surface *surface)
    248 {
    249 	_kernel_swi_regs regs;
    250 	int window_data[23];
    251     int	*window_block = window_data+1;
    252 	int x = (this->hidden->screen_width - surface->w) / 2;
    253 	int y = (this->hidden->screen_height - surface->h) / 2;
    254 	int xeig = this->hidden->xeig;
    255 	int yeig = this->hidden->yeig;
    256 
    257     mouseInWindow = 0;
    258 
    259 	/* Always delete the window and recreate on a change */
    260 	if (this->hidden->window_handle) WIMP_DeleteWindow(this);
    261 
    262 	/* Setup window co-ordinates */
    263    window_block[0] = x << xeig;
    264    window_block[1] = y << yeig;
    265    window_block[2] = window_block[0] + (surface->w << xeig);
    266    window_block[3] = window_block[1] + (surface->h << yeig);
    267 
    268 
    269    window_block[4] = 0;				  /* Scroll offsets */
    270    window_block[5] = 0;
    271    window_block[6] = -1;			  /* Open on top of window stack */
    272 
    273    window_block[7] = 0x85040042;      /* Window flags */
    274    if (riscos_closeaction != 0) window_block[7] |= 0x2000000;
    275 
    276    /* TODO: Take into account surface->flags */
    277 
    278    window_block[8] = 0xff070207;      /* Window colours */
    279    window_block[9] = 0x000c0103;
    280    window_block[10] = 0;                    /* Work area minimum */
    281    window_block[11] = -surface->h << yeig;
    282    window_block[12] = surface->w << xeig;   /* Work area maximum */
    283    window_block[13] = 0;
    284    window_block[14] = 0x2700013d;    /* Title icon flags */
    285    window_block[15] = 0x00003000;	 /* Work area flags - Mouse click down reported */
    286    window_block[16] = 1;             /* Sprite area control block pointer */
    287    window_block[17] = 0x00100010;	 /* Minimum window size (width & height) (16x16)*/
    288    window_block[18] = (int)this->hidden->title;    /* Title data */
    289    window_block[19] = -1;
    290    window_block[20] = 256;
    291    window_block[21] = 0;			 /* Number of icons */
    292 
    293    regs.r[1] = (unsigned int)(window_block);
    294 
    295    /* Create the window */
    296    if (_kernel_swi(Wimp_CreateWindow, &regs, &regs) == NULL)
    297    {
    298 	   this->hidden->window_handle = window_data[0] = regs.r[0];
    299 
    300 	   /* Show the window on the screen */
    301 	   regs.r[1] = (unsigned int)window_data;
    302        if (_kernel_swi(Wimp_OpenWindow, &regs, &regs) == NULL)
    303        {
    304           WIMP_SetFocus(this->hidden->window_handle);
    305        } else
    306        {
    307 		  WIMP_DeleteWindow(this);
    308 	   }
    309    }
    310 
    311    return this->hidden->window_handle;
    312 }
    313 
    314 /* Destroy the Window */
    315 
    316 void WIMP_DeleteWindow(_THIS)
    317 {
    318 	_kernel_swi_regs regs;
    319     regs.r[1] = (unsigned int)&(this->hidden->window_handle);
    320 	_kernel_swi(Wimp_DeleteWindow, &regs, &regs);
    321 	this->hidden->window_handle = 0;
    322 }
    323 
    324 
    325 void WIMP_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
    326 {
    327 	_kernel_swi_regs regs;
    328 	int update_block[12];
    329 	int xeig = this->hidden->xeig;
    330 	int yeig = this->hidden->yeig;
    331 	int j;
    332 	update_block[0] = this->hidden->window_handle;
    333 
    334 	for (j = 0; j < numrects; j++)
    335 	{
    336 		update_block[1] = rects[j].x << xeig; /* Min X */
    337 		update_block[4] = -(rects[j].y << yeig);
    338 		update_block[3] = update_block[1] + (rects[j].w << xeig);
    339 		update_block[2] = update_block[4] - (rects[j].h << yeig);
    340 
    341 		regs.r[1] = (int)update_block;
    342 		/* Update window can fail if called before first poll */
    343 		if (_kernel_swi(Wimp_UpdateWindow, &regs, &regs) == 0)
    344 		{
    345 			while (regs.r[0])
    346 			{
    347 				WIMP_PlotSprite(this, update_block[1], update_block[2]);
    348 				_kernel_swi(Wimp_GetRectangle, &regs, &regs);
    349 			}
    350 		}
    351 	}
    352 }
    353 
    354 
    355 int WIMP_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
    356 {
    357    unsigned int *pal = (unsigned int *)(this->hidden->bank[1]+60);
    358    int j;
    359    SDL_Rect update;
    360 
    361    pal += firstcolor*2;
    362    for (j = 0; j < ncolors; j++)
    363    {
    364       *pal = (((unsigned int)colors->r) << 8)
    365              + (((unsigned int)colors->g) << 16)
    366              + (((unsigned int)colors->b) << 24);
    367       pal[1] = *pal;
    368       pal += 2;
    369       colors++;
    370    }
    371 
    372    WIMP_SetupPlotInfo(this);
    373 
    374    /* Need to refresh the window */
    375    update.x = 0;
    376    update.y = 0;
    377    update.w = SDL_VideoSurface->w;
    378    update.h = SDL_VideoSurface->h;
    379    WIMP_UpdateRects(this, 1, &update);
    380 
    381 	return 1;
    382 }
    383 
    384 void WIMP_SetWMCaption(_THIS, const char *title, const char *icon)
    385 {
    386 	_kernel_swi_regs regs;
    387 
    388 	SDL_strlcpy(this->hidden->title, title, SDL_arraysize(this->hidden->title));
    389 
    390 	if (RISCOS_GetWimpVersion() < 380)
    391 	{
    392 		int block[6];
    393 
    394 		regs.r[1] = (int)block;
    395 		_kernel_swi(Wimp_GetCaretPosition, &regs, &regs);
    396 		if (block[0] == (int)this->hidden->window_handle)
    397 		{
    398 			regs.r[0] = -1;
    399 			_kernel_swi(Wimp_SetCaretPosition, &regs,&regs);
    400 		} else
    401 		{
    402 			regs.r[0] = this->hidden->window_handle;
    403 			regs.r[1] = -1;
    404 			regs.r[2] = -1;
    405 			regs.r[3] = -1;
    406 			_kernel_swi(Wimp_SetCaretPosition, &regs,&regs);
    407 		}
    408 		regs.r[0] = block[0];
    409 		regs.r[1] = block[1];
    410 		regs.r[2] = block[2];
    411 		regs.r[3] = block[3];
    412 		regs.r[4] = block[4];
    413 		regs.r[5] = block[5];
    414 		_kernel_swi(Wimp_SetCaretPosition, &regs,&regs);
    415 	} else
    416 	{
    417 		regs.r[0] = this->hidden->window_handle;
    418 		regs.r[1] = 0x4b534154; /* "TASK" */
    419 		regs.r[2] = 3; /* Redraw title */
    420 		_kernel_swi(Wimp_ForceRedraw, &regs, &regs);
    421 	}
    422 }
    423 
    424 void WIMP_RefreshDesktop(_THIS)
    425 {
    426    int width = this->hidden->screen_width << this->hidden->xeig;
    427    int height = this->hidden->screen_height << this->hidden->yeig;
    428    _kernel_swi_regs regs;
    429    regs.r[0] = -1; /* Whole screen */
    430    regs.r[1] = 0;
    431    regs.r[2] = 0;
    432    regs.r[3] = width;
    433    regs.r[4] = height;
    434    _kernel_swi(Wimp_ForceRedraw, &regs, &regs);
    435 }
    436 
    437 /* Toggle to window from full screen */
    438 int WIMP_ToggleFromFullScreen(_THIS)
    439 {
    440    int width = this->screen->w;
    441    int height = this->screen->h;
    442    int bpp = this->screen->format->BitsPerPixel;
    443    char *buffer = NULL;
    444    char *old_bank[2];
    445    char *old_alloc_bank;
    446 
    447    /* Ensure flags are OK */
    448    this->screen->flags &= ~(SDL_DOUBLEBUF|SDL_HWSURFACE);
    449 
    450    if (this->hidden->bank[0] == this->hidden->alloc_bank || riscos_backbuffer == 0)
    451    {
    452       /* Need to create a sprite for the screen and copy the data to it */
    453       char *data;
    454       buffer = WIMP_CreateBuffer(width, height, bpp);
    455       data = buffer + 60;         /* Start of sprite data */
    456       if (bpp == 8) data += 2048;  /* 8bpp sprite have palette first */
    457 
    458       if (buffer == NULL) return 0;
    459       SDL_memcpy(data, this->hidden->bank[0], width * height * this->screen->format->BytesPerPixel);
    460    }
    461    /* else We've switch to full screen before so we already have a sprite */
    462 
    463    old_bank[0] = this->hidden->bank[0];
    464    old_bank[1] = this->hidden->bank[1];
    465    old_alloc_bank = this->hidden->alloc_bank;
    466 
    467    if (buffer != NULL) this->hidden->alloc_bank = buffer;
    468 
    469    this->hidden->bank[1] = this->hidden->alloc_bank;
    470    this->hidden->bank[0] = this->hidden->bank[1] + 60; /* Start of sprite data */
    471    if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
    472 
    473    this->hidden->current_bank = 0;
    474    this->screen->pixels = this->hidden->bank[0];
    475 
    476    RISCOS_RestoreWimpMode();
    477    WIMP_ReadModeInfo(this);
    478    if (WIMP_SetupWindow(this, this->screen))
    479    {
    480       WIMP_SetDeviceMode(this);
    481       WIMP_SetupPlotInfo(this);
    482 
    483       if (riscos_backbuffer == 0) riscos_backbuffer = 1;
    484 
    485       if (buffer && old_alloc_bank) SDL_free(old_alloc_bank);
    486 
    487       return 1;
    488    } else
    489    {
    490       /* Drop back to full screen mode on failure */
    491       this->hidden->bank[0] = old_bank[0];
    492       this->hidden->bank[1] = old_bank[1];
    493       this->hidden->alloc_bank = old_alloc_bank;
    494       if (buffer) SDL_free(buffer);
    495 
    496       RISCOS_StoreWimpMode();
    497       FULLSCREEN_SetMode(width, height, bpp);
    498    }
    499 
    500    return 0;
    501 }
    502