00001 /* --------------------------------------------------------------------------- 00002 Phission : 00003 Realtime Vision Processing System 00004 00005 Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu) 00006 University of Massachusetts at Lowell, 00007 Laboratory for Artificial Intelligence and Robotics 00008 00009 This file is part of Phission. 00010 00011 Phission is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU Lesser General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 Phission is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU Lesser General Public License for more details. 00020 00021 You should have received a copy of the GNU Lesser General Public License 00022 along with Phission; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 ---------------------------------------------------------------------------*/ 00026 #ifdef HAVE_CONFIG_H 00027 #include <phissionconfig.h> 00028 #endif 00029 00030 #if defined(HAVE_UNISTD_H) 00031 #include <unistd.h> 00032 #endif 00033 00034 #include <phStandard.h> 00035 #include <ImageUtil.h> 00036 00037 #include <phSDLImageWindow.h> 00038 00039 #include <SDL.h> 00040 #include <SDL_thread.h> 00041 00042 #include <phError.h> 00043 #include <phMemory.h> 00044 #include <phPrint.h> 00045 00046 /* ---------------------------------------------------------------------- */ 00047 struct phSDLWindowInfo_t 00048 { 00049 Uint32 m_init_flags; 00050 00051 SDL_Rect m_screen_rect; 00052 SDL_Surface *m_screen_surface; 00053 00054 SDL_Rect m_image_rect; 00055 SDL_Surface *m_image_surface; 00056 00057 int m_fullscreen; 00058 SDL_Rect m_fullscreen_rect; 00059 SDL_Rect m_windowed_rect; 00060 00061 SDL_Color m_grayscale_colors[256]; 00062 }; 00063 00064 /* ---------------------------------------------------------------------- */ 00065 /* display/sdl/phSDLImageWindow.cpp 00066 * 00067 * SDLDisplay : cross platform fast image displaying utility 00068 * (cross platform except possibly the phImage class) 00069 * 00070 * This file has the C-ish routines for the SDL threads and SDL 00071 * interface code. 00072 * 00073 * ---------------------------------------------------------------------- */ 00074 /* ---------------------------------------------------------------------- */ 00075 #if phDONT_PRINT_ERRORS 00076 #define phSDL_ERR_PRINT(fmt, ...) 00077 #elif phNO_FUNCTION_VARIABLE 00078 #define phSDL_ERR_PRINT(fmt, ...) \ 00079 { \ 00080 fprintf(stderr, \ 00081 "(pid:%d %s:%d)\t*** ERROR *** " fmt ": %s\n", \ 00082 getpid(),__FILE__, __LINE__, \ 00083 ## __VA_ARGS__, SDL_GetError()); \ 00084 fflush(stderr); \ 00085 } 00086 #else 00087 #define phSDL_ERR_PRINT(fmt, ...) \ 00088 { \ 00089 fprintf(stderr, \ 00090 "(pid:%d %s:%d @ %s)\t*** ERROR *** " fmt ": %s\n", \ 00091 getpid(),__FILE__, __LINE__, function, \ 00092 ## __VA_ARGS__, SDL_GetError()); \ 00093 fflush(stderr); \ 00094 } 00095 #endif 00096 00097 /* ---------------------------------------------------------------------- */ 00098 #define phSDL_CHECK_NULLPTR(ptr,fmt, ...) \ 00099 { \ 00100 if (ptr == NULL) {\ 00101 phSDL_ERR_PRINT(fmt,##__VA_ARGS__);\ 00102 }\ 00103 } 00104 /* ---------------------------------------------------------------------- */ 00105 #define phSDL_RC(rc,action, ...) \ 00106 { \ 00107 if (rc < 0) \ 00108 { \ 00109 phSDL_ERR_PRINT( __VA_ARGS__ ); \ 00110 action; \ 00111 } \ 00112 } 00113 #define SDL_CHECK_RC(rc, ...) phSDL_RC(rc, goto error, __VA_ARGS__ ); 00114 #define SDL_BREAK_RC(rc, ...) phSDL_RC(rc, break, __VA_ARGS__ ); 00115 #define SDL_CONT_RC(rc, ...) phSDL_RC(rc, continue, __VA_ARGS__ ); 00116 #define SDL_PRINT_RC(rc, ...) phSDL_RC(rc, , __VA_ARGS__ ); 00117 00118 /* ---------------------------------------------------------------------- */ 00119 #define SDL_USER_THREAD_WAKEUP (SDL_USEREVENT + 0) 00120 00121 /* ---------------------------------------------------------------------------- 00122 * ------------------------------------------------------------------------- */ 00123 00124 #define LOCK_SURFACE(s) \ 00125 if (SDL_MUSTLOCK(s)) \ 00126 { \ 00127 if (SDL_LockSurface(s) == -1) \ 00128 { \ 00129 SDL_PRINT_RC(-1,"SDL_LockSurface failed."); \ 00130 } \ 00131 } 00132 00133 #define UNLOCK_SURFACE(s) \ 00134 if (SDL_MUSTLOCK(s)) SDL_UnlockSurface(s); 00135 00136 #define SDL_MIN_WIDTH 20 00137 #define SDL_MIN_HEIGHT 20 00138 00139 /* ---------------------------------------------------------------------- */ 00140 #if SDL_BYTEORDER == SDL_BIG_ENDIAN 00141 00142 #if __BYTE_ORDER != __BIG_ENDIAN 00143 #error "SDL_BYTEORDER Knows something about endianness that we don\'t : BIG" 00144 #endif 00145 00146 #else /* Little Endian */ 00147 00148 #if __BYTE_ORDER != __LITTLE_ENDIAN 00149 #error "SDL_BYTEORDER Knows something about endianness that we don\'t : LITTLE" 00150 #endif 00151 00152 #endif 00153 00154 /* ------------------------------------------------------------------------- */ 00155 int EventFilter(const SDL_Event *event) 00156 { 00157 switch(event->type) 00158 { 00159 case SDL_ACTIVEEVENT: 00160 case SDL_VIDEORESIZE: 00161 case SDL_VIDEOEXPOSE: 00162 case SDL_QUIT: 00163 case SDL_KEYDOWN: 00164 case SDL_KEYUP: 00165 case SDL_SYSWMEVENT: 00166 return 1; 00167 00168 case SDL_USEREVENT: 00169 if (event->user.code == 0) 00170 return 0; 00171 else 00172 return 1; 00173 00174 case SDL_MOUSEMOTION: 00175 case SDL_MOUSEBUTTONDOWN: 00176 case SDL_MOUSEBUTTONUP: 00177 case SDL_JOYAXISMOTION: 00178 case SDL_JOYBALLMOTION: 00179 case SDL_JOYHATMOTION: 00180 case SDL_JOYBUTTONDOWN: 00181 case SDL_JOYBUTTONUP: 00182 return 0; 00183 } 00184 return 0; 00185 } 00186 00187 /* ------------------------------------------------------------------------- */ 00188 phSDLImageWindow::phSDLImageWindow( uint32_t x, uint32_t y, 00189 uint32_t w, uint32_t h, 00190 char *title, 00191 uint32_t flags ) : 00192 phImageWindow(x,y,w,h,title,flags ) 00193 { 00194 phFUNCTION("phSDLImageWindow::phSDLImageWindow") 00195 00196 uint32_t i = 0; 00197 /*uint32_t title_len = (title != NULL) ? strlen(title) + 20 : 50;*/ 00198 00199 rc = this->lock(); 00200 phPRINT_RC(rc,NULL,"this->lock()"); 00201 00202 this->m_info = (phSDLWindowInfo_t *)phCalloc(1, 00203 sizeof(phSDLWindowInfo_t)); 00204 phPRINT_NULLPTR(this->m_info,NULL, 00205 "phCalloc failed to allocate phSDLWindowInfo"); 00206 00207 this->m_currentDepth = 0; 00208 this->m_currentFormat = phImageNOFORMAT; 00209 00210 this->m_info->m_init_flags = SDL_INIT_VIDEO | 00211 SDL_INIT_NOPARACHUTE | 00212 SDL_INIT_EVENTTHREAD; 00213 00214 phMemset(&this->m_info->m_screen_rect, 0,sizeof(SDL_Rect)); 00215 phMemset(&this->m_info->m_windowed_rect, 0,sizeof(SDL_Rect)); 00216 phMemset(&this->m_info->m_fullscreen_rect, 0,sizeof(SDL_Rect)); 00217 00218 this->m_info->m_fullscreen = 0; 00219 this->m_info->m_screen_surface = NULL; 00220 this->m_info->m_image_surface = NULL; 00221 this->m_info->m_image_rect.x = 00222 this->m_info->m_image_rect.y = 0; 00223 this->m_info->m_image_rect.w = w; 00224 this->m_info->m_image_rect.h = h; 00225 00226 this->setName("phSDLImageWindow"); 00227 00228 if (this->m_title == NULL) 00229 { 00230 this->setTitle("Phission: phSDLImageWindow"); 00231 } 00232 00233 this->m_formats = phSDLImageWindow_ValidFormats; 00234 00235 for (i = 0; i < 256; i++) { 00236 this->m_info->m_grayscale_colors[i].r = 00237 this->m_info->m_grayscale_colors[i].g = 00238 this->m_info->m_grayscale_colors[i].b = i; 00239 } 00240 00241 /*error:*/ 00242 rc = this->unlock(); 00243 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00244 00245 return; 00246 } 00247 00248 /* ------------------------------------------------------------------------- */ 00249 phSDLImageWindow::~phSDLImageWindow() 00250 { 00251 phFUNCTION("phSDLImageWindow::~phSDLImageWindow") 00252 00253 rc = this->lock(); 00254 phPRINT_RC(rc,NULL,"this->lock();"); 00255 00256 if (this->m_info->m_image_surface) 00257 { 00258 SDL_FreeSurface(this->m_info->m_image_surface); 00259 } 00260 00261 phFree(this->m_info); 00262 } 00263 00264 /* ---------------------------------------------------------------------------- 00265 * image_window_init -- initialize the buffer surface; buffer is drawn to 00266 * ------------------------------------------------------------------------- */ 00267 int phSDLImageWindow::image_window_init() 00268 { 00269 phFUNCTION("phSDLImageWindow::image_window_init") 00270 uint32_t depth = 0; 00271 int locked = 0; 00272 int readLocked = 0; 00273 uint32_t format = phImageNOFORMAT; 00274 char *whichone = "unknown"; 00275 00276 rc = this->lock(); 00277 phCHECK_RC(rc,NULL,"this->lock()"); 00278 locked = 1; 00279 00280 this->m_info->m_image_rect.w = this->m_info->m_screen_rect.w; 00281 this->m_info->m_image_rect.h = this->m_info->m_screen_rect.h; 00282 00283 if (this->m_info->m_image_surface) { 00284 SDL_FreeSurface(this->m_info->m_image_surface); 00285 } 00286 00287 rc = this->m_image.readLock(); 00288 phCHECK_RC(rc,NULL,"this->m_image.readLock() failed."); 00289 readLocked = 1; 00290 00291 format = this->m_image.getFormat(); 00292 00293 if (format & (phSDLImageWindow_ValidFormats)) 00294 { 00295 switch (format) 00296 { 00297 case phImageRGB24: 00298 case phImageBGR24: 00299 depth = 24; 00300 break; 00301 case phImageABGR32: 00302 case phImageRGBA32: 00303 case phImageBGRA32: 00304 depth = 32; 00305 break; 00306 case phImageGREY8: 00307 depth = 8; 00308 break; 00309 } 00310 /* 00311 phPROGRESS("%s - 0x%08x:0x%08x:0x%08x:0x%08x\n", 00312 phImageFormatToString(format), 00313 phImageFormatTo32BitMask(format,phCHANNEL_RED), 00314 phImageFormatTo32BitMask(format,phCHANNEL_GREEN), 00315 phImageFormatTo32BitMask(format,phCHANNEL_BLUE), 00316 phImageFormatTo32BitMask(format,phCHANNEL_ALPHA) ); 00317 */ 00318 if (depth > 8) 00319 { 00320 whichone = "depth > 8"; 00321 this->m_info->m_image_surface = 00322 SDL_CreateRGBSurface(SDL_HWSURFACE, 00323 this->m_info->m_image_rect.w, 00324 this->m_info->m_image_rect.h, 00325 depth, 00326 phImageFormatTo32BitMask(format,phCHANNEL_RED), 00327 phImageFormatTo32BitMask(format,phCHANNEL_GREEN), 00328 phImageFormatTo32BitMask(format,phCHANNEL_BLUE), 00329 phImageFormatTo32BitMask(format,phCHANNEL_ALPHA) ); 00330 00331 } 00332 else if (depth > 0) 00333 { 00334 whichone = "0 < depth <= 8"; 00335 this->m_info->m_image_surface = 00336 SDL_CreateRGBSurface(SDL_SWSURFACE, 00337 this->m_info->m_image_rect.w, 00338 this->m_info->m_image_rect.h, 00339 depth, 0,0,0,0); 00340 00341 rc = SDL_SetColors(this->m_info->m_image_surface, 00342 this->m_info->m_grayscale_colors, 0, 256); 00343 SDL_PRINT_RC(rc,"SDL_SetColors"); 00344 } 00345 else 00346 { 00347 whichone = "depth == 0"; 00348 this->m_info->m_image_surface = NULL; 00349 } 00350 //phPROGRESS("%s\n",whichone); 00351 phSDL_CHECK_NULLPTR( this->m_info->m_image_surface, 00352 "SDL_CreateRGBSurface(%s) failed", 00353 whichone ); 00354 00355 /* set up the blit coordinates for the image */ 00356 this->m_info->m_image_rect.x = 0; 00357 this->m_info->m_image_rect.y = 0; 00358 } 00359 00360 if (depth != 0) 00361 { 00362 this->m_currentDepth = depth; 00363 } 00364 00365 if (format != (uint32_t)phImageNOFORMAT) 00366 { 00367 //phPROGRESS("New Format: %s\n", 00368 // phImageFormatToString(format)); 00369 this->m_currentFormat = format; 00370 } 00371 00372 rc = this->m_image.rwUnlock(); 00373 readLocked = 0; 00374 phCHECK_RC(rc,NULL,"this->m_image.rwUnlock() failed."); 00375 00376 rc = this->unlock(); 00377 locked = 0; 00378 phCHECK_RC(rc,NULL,"this->unlock() failed."); 00379 00380 return phSUCCESS; 00381 00382 error: 00383 if (readLocked) 00384 { 00385 rc = this->m_image.rwUnlock(); 00386 readLocked = 0; 00387 //phPRINT_RC(rc,NULL,"this->m_image.rwUnlock() failed."); 00388 } 00389 00390 if (locked) 00391 { 00392 rc = this->unlock(); 00393 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00394 } 00395 00396 return phFAIL; 00397 } 00398 00399 /* ---------------------------------------------------------------------------- 00400 * window_init -- initialize the screen and image surfaces 00401 * ------------------------------------------------------------------------- */ 00402 int phSDLImageWindow::window_init( uint32_t x, 00403 uint32_t y, 00404 uint32_t w, 00405 uint32_t h ) 00406 { 00407 phFUNCTION("phSDLImageWindow::window_init") 00408 00409 uint32_t flags = 0; 00410 00411 /* create the "screen," a WIDTHxHEIGHT window. 00412 * passing "0" for bit depth means SDL will pick the best available, 00413 * usually 32 bits-per-pixel. the SDL_SWSURFACE flag means create the 00414 * screen surface in system memory. Always use SDL_DOUBLEBUF, it makes 00415 * for smooth video 00416 */ 00417 rc = this->lock(); 00418 phPRINT_RC(rc,NULL,"this->lock()"); 00419 00420 flags = SDL_HWSURFACE | 00421 ((this->m_info->m_fullscreen) ? SDL_FULLSCREEN : SDL_RESIZABLE ) | 00422 SDL_DOUBLEBUF; 00423 00424 if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) 00425 { 00426 SDL_Rect **modes = SDL_ListModes(NULL,flags); 00427 00428 this->m_info->m_fullscreen_rect.w = w; 00429 this->m_info->m_fullscreen_rect.h = h; 00430 00431 if ((modes != (SDL_Rect **)0) && 00432 (modes != (SDL_Rect **)-1)) 00433 { 00434 int i = 0; 00435 int neww = 0; 00436 int newh = 0; 00437 for (i = 0; modes[i]; ++i) 00438 { 00439 if (modes[i]->w > neww) 00440 { 00441 neww = modes[i]->w; 00442 newh = modes[i]->h; 00443 } 00444 } 00445 if ((neww != 0) && (newh != 0)) 00446 { 00447 this->m_info->m_fullscreen_rect.w = neww; 00448 this->m_info->m_fullscreen_rect.h = newh; 00449 } 00450 } 00451 #if 0 00452 if (this->m_info->m_fullscreen_rect.w < this->m_min_width) 00453 this->m_info->m_fullscreen_rect.w = this->m_min_width; 00454 if (this->m_info->m_fullscreen_rect.h < this->m_min_height) 00455 this->m_info->m_fullscreen_rect.w = this->m_min_height; 00456 #endif 00457 this->m_info->m_screen_rect = this->m_info->m_fullscreen_rect; 00458 SDL_ShowCursor(SDL_DISABLE); 00459 } 00460 else 00461 { 00462 if ((w == this->m_info->m_fullscreen_rect.w) && 00463 (h == this->m_info->m_fullscreen_rect.h)) 00464 { 00465 this->m_info->m_fullscreen_rect.w = 0; 00466 this->m_info->m_fullscreen_rect.h = 0; 00467 SDL_ShowCursor(SDL_ENABLE); 00468 } 00469 else 00470 { 00471 this->m_info->m_windowed_rect.w = w; 00472 this->m_info->m_windowed_rect.h = h; 00473 } 00474 00475 if (this->m_info->m_windowed_rect.w < SDL_MIN_WIDTH) 00476 this->m_info->m_windowed_rect.w = SDL_MIN_WIDTH; 00477 if (this->m_info->m_windowed_rect.h < SDL_MIN_HEIGHT) 00478 this->m_info->m_windowed_rect.h = SDL_MIN_HEIGHT; 00479 00480 this->m_info->m_screen_rect = this->m_info->m_windowed_rect; 00481 this->m_info->m_screen_rect.x = x; 00482 this->m_info->m_screen_rect.y = y; 00483 } 00484 this->m_w = this->m_info->m_screen_rect.w; 00485 this->m_h = this->m_info->m_screen_rect.h; 00486 this->m_info->m_screen_surface = 00487 SDL_SetVideoMode(this->m_info->m_screen_rect.w, /* width */ 00488 this->m_info->m_screen_rect.h, /* height */ 00489 32, /* bit depth */ 00490 flags ); 00491 phSDL_CHECK_NULLPTR( this->m_info->m_screen_surface, 00492 "SDL_SetVideoMode() failed"); 00493 /* set the title bar text */ 00494 if (this->m_title == NULL) 00495 { 00496 SDL_WM_SetCaption("display","display"); 00497 } 00498 else 00499 SDL_WM_SetCaption(this->m_title,this->m_title); 00500 00501 rc = this->image_window_init(); 00502 phCHECK_RC(rc,NULL,"image_window_init failed."); 00503 00504 rc = this->unlock(); 00505 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00506 00507 return phSUCCESS; 00508 00509 error: 00510 rc = this->unlock(); 00511 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00512 00513 return phFAIL; 00514 } 00515 /* ---------------------------------------------------------------------- */ 00516 int phSDLImageWindow::private_hide() 00517 { 00518 /* 00519 * We are locked when we get into a "private" method; Locking is done 00520 * as a policy in any public interface method that calls a private 00521 * (implementation specific) method 00522 int locked = 1; 00523 */ 00524 return phSUCCESS; 00525 } 00526 00527 /* ---------------------------------------------------------------------- */ 00528 int phSDLImageWindow::private_show() 00529 { 00530 /* 00531 * We are locked when we get into a "private" method; Locking is done 00532 * as a policy in any public interface method that calls a private 00533 * (implementation specific) method 00534 int locked = 1; 00535 */ 00536 return phSUCCESS; 00537 } 00538 00539 /* ------------------------------------------------------------------------- */ 00540 int phSDLImageWindow::private_redraw() 00541 { 00542 phFUNCTION("phSDLImageWindow::private_redraw") 00543 uint32_t new_depth = 0; 00544 uint32_t new_format = phImageNOFORMAT; 00545 int writeLocked = 0; 00546 /* 00547 * We are locked when we get into a "private" method; Locking is done 00548 * as a policy in any public interface method that calls a private 00549 * (implementation specific) method 00550 int locked = 1; 00551 */ 00552 00553 rc = this->m_image.writeLock(); 00554 phCHECK_RC(rc, NULL, "this->m_image.writeLock() failed"); 00555 writeLocked = 1; 00556 00557 if ((!this->m_image.isNull()) && (SDL_GetAppState() & SDL_APPACTIVE)) 00558 { 00559 rc = this->m_image.convert(this->getFormats()); 00560 phPRINT_RC(rc,NULL,"m_image.convert() failed"); 00561 00562 new_format = this->m_image.getFormat(); 00563 00564 /* new_depth or new_format used to not accept a format type */ 00565 switch (new_format) 00566 { 00567 case phImageRGB24: 00568 case phImageBGR24: 00569 new_depth = 24; 00570 break; 00571 case phImageABGR32: 00572 case phImageRGBA32: 00573 case phImageBGRA32: 00574 new_depth = 32; 00575 break; 00576 case phImageGREY8: 00577 new_depth = 8; 00578 break; 00579 default: 00580 new_depth = 0; 00581 new_format = phImageNOFORMAT; 00582 } 00583 00584 if (((new_depth != this->m_currentDepth) && 00585 (new_depth != 0)) 00586 || 00587 ((new_format != this->m_currentFormat) && 00588 (new_format != (uint32_t)phImageNOFORMAT))) 00589 { 00590 rc = this->image_window_init(); 00591 phPRINT_RC(rc,NULL,"image_window_init() failed."); 00592 } 00593 if ((new_depth != 0) && (new_format != (uint32_t)phImageNOFORMAT)) 00594 { 00595 /* maintain frames-per-second */ 00596 this->tickFrame(); 00597 00598 if ((this->m_info->m_image_surface) && 00599 (this->m_info->m_screen_surface)) 00600 { 00601 LOCK_SURFACE(this->m_info->m_image_surface); 00602 this->m_image.resize(this->m_info->m_image_surface->w, 00603 this->m_info->m_image_surface->h); 00604 memcpy( (void *)this->m_info->m_image_surface->pixels, 00605 (void *)this->m_image.getData(), 00606 this->m_image.getSize()); 00607 UNLOCK_SURFACE(this->m_info->m_image_surface); 00608 00609 /* now copy the image back to the screen for display */ 00610 SDL_BlitSurface(this->m_info->m_image_surface, 00611 NULL, 00612 this->m_info->m_screen_surface, 00613 &(this->m_info->m_image_rect)); 00614 SDL_Flip(this->m_info->m_screen_surface); 00615 } 00616 } 00617 } 00618 00619 /* unlock the mutexes */ 00620 rc = this->m_image.rwUnlock(); 00621 writeLocked = 0; 00622 phCHECK_RC(rc,NULL, "this->m_image.rwUnlock() failed"); 00623 00624 return phSUCCESS; 00625 error: 00626 if (writeLocked) 00627 { 00628 rc = this->m_image.rwUnlock(); 00629 phPRINT_RC(rc,NULL, "this->m_image.rwUnlock() failed"); 00630 writeLocked = 0; 00631 } 00632 00633 return phFAIL; 00634 } 00635 00636 /* ------------------------------------------------------------------------- */ 00637 int phSDLImageWindow::private_update() 00638 { 00639 phFUNCTION("phSDLImageWindow::private_update") 00640 int writeLocked = 0; 00641 /* 00642 * We are locked when we get into a "private" method; Locking is done 00643 * as a policy in any public interface method that calls a private 00644 * (implementation specific) method 00645 int locked = 1; 00646 */ 00647 00648 rc = this->m_image.writeLock(); 00649 phCHECK_RC(rc,NULL,"this->m_image.writeLock()"); 00650 writeLocked = 1; 00651 00652 if (this->m_image.isNull() == 0) 00653 { 00654 rc = this->private_redraw(); 00655 phPRINT_RC(rc,NULL,"this->private_redraw() failed."); 00656 } 00657 00658 rc = this->m_image.rwUnlock(); 00659 writeLocked = 0; 00660 phCHECK_RC(rc,NULL,"this->m_image.rwUnlock()"); 00661 00662 return phSUCCESS; 00663 error: 00664 if (writeLocked) 00665 { 00666 rc = this->m_image.rwUnlock(); 00667 phPRINT_RC(rc,NULL,"this->m_image.rwUnlock()"); 00668 writeLocked = 0; 00669 } 00670 00671 return phFAIL; 00672 } 00673 00674 /* ------------------------------------------------------------------------- */ 00675 /* this method is used to calculate the mapping from the requested resize 00676 * dims to the actual implementable resize values. */ 00677 /* ------------------------------------------------------------------------- */ 00678 int phSDLImageWindow::calc_resize(uint32_t w,uint32_t h, 00679 uint32_t *tw, uint32_t *th ) 00680 { 00681 phFUNCTION("phSDLImageWindow::calc_width_resize") 00682 uint32_t step = 0; 00683 uint32_t ow = w; 00684 uint32_t oh = h; 00685 int retrc = phSUCCESS; 00686 00687 rc = this->lock(); 00688 phPRINT_RC(rc,NULL,"this->lock()"); 00689 00690 step = (this->m_currentDepth / 8) + 1; 00691 00692 /* Make sure the image can't be made smaller than 00693 * the original, it's just pointless to waste 00694 * CPU time making an image smaller when it's faster 00695 * to just blit it to memeory */ 00696 if ((uint32_t)w < this->m_min_width) w = this->m_min_width; 00697 if ((uint32_t)h < this->m_min_height)h = this->m_min_height; 00698 00699 /* For some reason, this has to be done to make sure the 00700 * scaling works */ 00701 if (w % step) w += step - (w % step); 00702 if (h % step) h += step - (h % step); 00703 00704 if ((uint32_t)w < this->m_min_width) w = this->m_min_width; 00705 if ((uint32_t)h < this->m_min_height) h = this->m_min_height; 00706 00707 *tw = w; 00708 *th = h; 00709 00710 if ((w != ow) || (h != oh)) retrc = 1; 00711 00712 rc = this->unlock(); 00713 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00714 00715 return retrc; 00716 } 00717 00718 /* ------------------------------------------------------------------------- */ 00719 int phSDLImageWindow::private_resize(uint32_t w, uint32_t h) 00720 { 00721 phFUNCTION("phSDLImageWindow::private_resize") 00722 int writeLocked = 0; 00723 /* 00724 * We are locked when we get into a "private" method; Locking is done 00725 * as a policy in any public interface method that calls a private 00726 * (implementation specific) method 00727 int locked = 1; 00728 */ 00729 00730 rc = this->m_image.writeLock(); 00731 phCHECK_RC(rc,NULL,"this->m_image.writeLock() failed."); 00732 writeLocked = 1; 00733 00734 rc = this->calc_resize(w,h,&w,&h); 00735 phPRINT_RC(rc,NULL,"this->calc_resize() failed."); 00736 00737 if ((w != this->getWidth()) || 00738 (h != this->getHeight())|| 00739 (rc == 1)) 00740 { 00741 /* in between the update call in the Display Interface, 00742 (which will potentially have an invalid format) 00743 and the actual call to 'update', this could potentially 00744 be called and the format could be unsupported. 00745 Should we convert it? 00746 */ 00747 if (!this->m_image.isNull()) 00748 { 00749 rc = this->m_image.convert(this->getFormats()); 00750 phPRINT_RC(rc,NULL,"m_image.convert() failed"); 00751 } 00752 rc = this->window_init(this->m_info->m_screen_rect.x, 00753 this->m_info->m_screen_rect.y, 00754 w, h); 00755 phCHECK_RC(rc,NULL,"this->window_init failed"); 00756 00757 rc = this->private_redraw(); 00758 phCHECK_RC(rc,NULL,"private_redraw() failed."); 00759 } 00760 00761 rc = this->m_image.rwUnlock(); 00762 writeLocked = 0; 00763 phCHECK_RC(rc,NULL,"this->m_image.rwUnlock() failed."); 00764 00765 return phSUCCESS; 00766 error: 00767 00768 if (writeLocked) 00769 { 00770 rc = this->m_image.rwUnlock(); 00771 phPRINT_RC(rc,NULL,"this->m_image.rwUnlock() failed."); 00772 writeLocked = 0; 00773 } 00774 00775 return phFAIL; 00776 } 00777 00778 /* ---------------------------------------------------------------------- */ 00779 int phSDLImageWindow::private_move( int32_t x, int32_t y ) 00780 { 00781 /* 00782 * We are locked when we get into a "private" method; Locking is done 00783 * as a policy in any public interface method that calls a private 00784 * (implementation specific) method 00785 int locked = 1; 00786 */ 00787 return phSUCCESS; 00788 } 00789 00790 /* ---------------------------------------------------------------------- */ 00791 int phSDLImageWindow::private_minsize( uint32_t min_w, uint32_t min_h) 00792 { 00793 /* 00794 * We are locked when we get into a "private" method; Locking is done 00795 * as a policy in any public interface method that calls a private 00796 * (implementation specific) method 00797 int locked = 1; 00798 */ 00799 return phSUCCESS; 00800 } 00801 00802 00803 /* ---------------------------------------------------------------------- */ 00804 int phSDLImageWindow::wakeup() 00805 { 00806 phFUNCTION("phSDLImageWindow::wakeup") 00807 00808 int retrc = phSUCCESS; 00809 SDL_Event wakeup_event; 00810 uint32_t tries = 0; 00811 uint32_t max_tries = 1000; 00812 00813 /* Setup the wakeup event */ 00814 wakeup_event.type = SDL_USER_THREAD_WAKEUP; 00815 wakeup_event.user.code = 1; /* Must be 1 to prevent filtering */ 00816 00817 do 00818 { 00819 rc = SDL_PushEvent(&wakeup_event); 00820 } 00821 while ((rc == -1) && (tries++ < max_tries)); 00822 00823 if (rc == -1) 00824 { 00825 phPRINT_RC(rc,NULL,"SDL_PushEvent failed to post wakeup_event"); 00826 retrc = phFAIL; 00827 } 00828 else 00829 { 00830 retrc = phSUCCESS; 00831 } 00832 00833 this->m_image.wakeup_self(); 00834 00835 // rc = this->phImageWindow::wakeup(); 00836 phPRINT_RC(rc,NULL,"this->phImageWindow::wakeup()"); 00837 00838 return retrc; 00839 } 00840 00841 /* ---------------------------------------------------------------------- */ 00842 int phSDLImageWindow::cleanup() 00843 { 00844 /* stop SDL */ 00845 SDL_Quit(); 00846 00847 return phSUCCESS; 00848 } 00849 00850 /* ---------------------------------------------------------------------- */ 00851 int phSDLImageWindow::run() 00852 { 00853 phFUNCTION("phSDLImageWindow::run") 00854 00855 int visible = 0; 00856 int redraw = 0; 00857 int sdl_started = 0; 00858 00859 SDL_Event event; /* event object */ 00860 00861 short keysymdown[SDLK_LAST]; 00862 memset(keysymdown,0,sizeof(keysymdown)); 00863 00864 DEBUG_PRINT("Thread started\n"); 00865 00866 /* start SDL */ 00867 /* initialize the SDL subsystem */ 00868 rc = SDL_Init(this->m_info->m_init_flags); 00869 SDL_CHECK_RC(rc, "SDL_Init() failed"); 00870 sdl_started = 1; 00871 00872 /* Filter out unused events */ 00873 SDL_SetEventFilter(EventFilter); 00874 SDL_EventState(SDL_MOUSEMOTION,SDL_IGNORE); 00875 SDL_EventState(SDL_MOUSEBUTTONDOWN,SDL_IGNORE); 00876 SDL_EventState(SDL_MOUSEBUTTONUP,SDL_IGNORE); 00877 SDL_EventState(SDL_JOYAXISMOTION,SDL_IGNORE); 00878 SDL_EventState(SDL_JOYBALLMOTION,SDL_IGNORE); 00879 SDL_EventState(SDL_JOYHATMOTION,SDL_IGNORE); 00880 SDL_EventState(SDL_JOYBUTTONDOWN,SDL_IGNORE); 00881 SDL_EventState(SDL_JOYBUTTONUP,SDL_IGNORE); 00882 00883 /* initialize the display */ 00884 rc = this->window_init(this->m_x,this->m_y,this->m_w,this->m_h); 00885 phCHECK_RC(rc,NULL, "window_init() failed"); 00886 00887 /* int SDL_EnableKeyRepeat(int delay, int interval);*/ 00888 /* SDL_DEFAULT_REPEAT_DELAY and SDL_DEFAULT_REPEAT_INTERVAL */ 00889 rc = SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 00890 SDL_DEFAULT_REPEAT_INTERVAL); 00891 SDL_CHECK_RC(rc,"SDL_EnableKeyRepeat"); 00892 00893 rc = this->signal_running(); 00894 phCHECK_RC(rc,NULL,"this->signal_running()"); 00895 00896 while (this->isRunning()) 00897 { 00898 if (SDL_WaitEvent(&event) == 1) 00899 { 00900 switch (event.type) { 00901 /* Used to clean up blocking event thread */ 00902 case SDL_USER_THREAD_WAKEUP: 00903 break; 00904 00905 case SDL_QUIT: /* user closed the window */ 00906 this->setRunning(0); 00907 this->m_image.wakeup_self(); 00908 break; 00909 00910 case SDL_KEYDOWN: /* user hit escape */ 00911 if (keysymdown[event.key.keysym.sym] < 2) 00912 keysymdown[event.key.keysym.sym]++; 00913 00914 break; 00915 00916 case SDL_KEYUP: 00917 keysymdown[event.key.keysym.sym] = 0; 00918 break; 00919 00920 case SDL_VIDEORESIZE: /* resize the window */ 00921 { 00922 uint32_t w = event.resize.w; 00923 uint32_t h = event.resize.h; 00924 00925 rc = this->lock(); 00926 phPRINT_RC(rc,NULL,"this->lock() failed."); 00927 00928 /* The m_w and m_h members will be set 00929 through this call */ 00930 rc = this->private_resize(w,h); 00931 phPRINT_RC(rc,NULL,"this->private_resize() failed."); 00932 00933 rc = this->unlock(); 00934 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00935 } 00936 break; 00937 00938 case SDL_VIDEOEXPOSE: 00939 redraw = 1; 00940 break; 00941 00942 case SDL_ACTIVEEVENT: 00943 if (event.active.state == SDL_APPACTIVE) 00944 { 00945 DEBUG_PRINT("if (event.active.state == SDL_APPACTIVE)"); 00946 if ((visible != event.active.gain) && 00947 (visible == 0)) 00948 { 00949 redraw = 1; 00950 } 00951 00952 visible = event.active.gain; 00953 } 00954 break; 00955 } 00956 00957 if (keysymdown[SDLK_ESCAPE] || keysymdown[SDLK_q]) 00958 { 00959 this->setRunning(0); 00960 this->m_image.wakeup_self(); 00961 } 00962 00963 if ((redraw) && (visible)) 00964 { 00965 redraw = 0; 00966 rc = this->lock(); 00967 phPRINT_RC(rc,NULL,"this->lock() failed."); 00968 00969 rc = this->private_redraw(); 00970 phPRINT_RC(rc,NULL,"this->private_resize() failed."); 00971 00972 rc = this->unlock(); 00973 phPRINT_RC(rc,NULL,"this->unlock() failed."); 00974 } 00975 } 00976 } 00977 00978 DEBUG_PRINT("Thread returning cleanly\n"); 00979 00980 00981 return phSUCCESS; 00982 error: 00983 phPROGRESS("Thread returning with error\n"); 00984 00985 if (sdl_started == 1) 00986 { 00987 /* stop SDL */ 00988 SDL_Quit(); 00989 } 00990 rc = this->signal_error(); 00991 phPRINT_RC(rc,NULL,"this->signal_error()"); 00992 00993 return phFAIL; 00994 } 00995 00996
Copyright (C) 2002 - 2007 |
Philip D.S. Thoren ( pthoren@users.sourceforge.net ) University Of Massachusetts at Lowell Robotics Lab |