src/video/riscos/SDL_wimpvideo.c
changeset 630 550bccdf04bd
child 634 44d574ed4780
equal deleted inserted replaced
629:3fa401bb4bb5 630:550bccdf04bd
       
     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 }