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