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, ®s, ®s); 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, ®s, ®s) == 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, ®s, ®s) == 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, ®s, ®s); 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, ®s, ®s) == 0) 344 { 345 while (regs.r[0]) 346 { 347 WIMP_PlotSprite(this, update_block[1], update_block[2]); 348 _kernel_swi(Wimp_GetRectangle, ®s, ®s); 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, ®s, ®s); 396 if (block[0] == (int)this->hidden->window_handle) 397 { 398 regs.r[0] = -1; 399 _kernel_swi(Wimp_SetCaretPosition, ®s,®s); 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, ®s,®s); 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, ®s,®s); 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, ®s, ®s); 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, ®s, ®s); 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