src/video/riscos/SDL_wimpvideo.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 14 Jun 2003 07:18:40 +0000
changeset 634 44d574ed4780
parent 630 550bccdf04bd
child 769 b8d311d90021
permissions -rw-r--r--
Date: Thu, 05 Jun 2003 09:36:40 +0100
From: "alan buckley" <alan_baa@hotmail.com>
Subject: Modification for RISC OS SDL port

My name is Alan Buckley and I have been working on the RISC OS SDL port.

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