comparison src/video/riscos/SDL_riscosFullScreenVideo.c @ 630:550bccdf04bd

Added initial support for RISC OS (thanks Peter Naulls!)
author Sam Lantinga <slouken@libsdl.org>
date Thu, 29 May 2003 04:44:13 +0000
parents
children b8d311d90021
comparison
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 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 }