![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 // Uncomment next line to disable shared memory features if you have not libXext 00030 // (http://www.xfree86.org/current/mit-shm.html) 00031 //#define X_NOSHMEM 00032 00033 #include "video.h" 00034 #include <string.h> 00035 #include <stdio.h> 00036 #include <stdlib.h> 00037 #include <math.h> 00038 #include <X11/Xlib.h> 00039 #include <X11/Xutil.h> 00040 #include <X11/keysym.h> 00041 #include <sys/time.h> 00042 #include <signal.h> 00043 #include <pthread.h> 00044 00045 #ifndef X_NOSHMEM 00046 #include <errno.h> 00047 #include <X11/extensions/XShm.h> 00048 #include <sys/ipc.h> 00049 #include <sys/shm.h> 00050 00051 static XShmSegmentInfo shmseginfo; 00052 static Pixmap pixmap = 0; 00053 #endif 00054 static char *display_name = NULL; 00055 static Display *dpy = NULL; 00056 static Screen *scrn; 00057 static Visual *vis; 00058 static Colormap cmap; 00059 static GC gc; 00060 static Window win, rootW; 00061 static int dispdepth = 0; 00062 static XGCValues xgcv; 00063 static XImage *ximage; 00064 static int x_error = 0; 00065 static int vidtype = 3; 00066 static int g_sizex, g_sizey; 00067 static video *g_video = 0; 00068 static unsigned int *g_pImg = 0; 00069 static int g_fps = 0; 00070 struct timeval g_time; 00071 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 00072 Atom _XA_WM_DELETE_WINDOW = 0;// like in Xatom.h 00073 00075 00076 video::video() 00077 { 00078 assert(g_video == 0); 00079 g_video = this; title = "Video"; calc_fps = running = false; updating = true; 00080 } 00081 00082 inline void mask2bits(unsigned int mask, unsigned int &save, char &shift) 00083 { 00084 save = mask; if(!mask) { shift = dispdepth/3; return; } 00085 shift = 0; while(!(mask&1)) ++shift, mask >>= 1; 00086 int bits = 0; while(mask&1) ++bits, mask >>= 1; 00087 shift += bits - 8; 00088 } 00089 00090 int xerr_handler(Display*, XErrorEvent *error) 00091 { 00092 x_error = error->error_code; 00093 if(g_video) g_video->running = false; 00094 return 0; 00095 } 00096 00097 bool video::init_window(int xsize, int ysize) 00098 { 00099 { //enclose local variables before fail label 00100 g_sizex = xsize; g_sizey = ysize; 00101 00102 // Open the display 00103 if (!dpy) { 00104 dpy = XOpenDisplay(display_name); 00105 if (!dpy) { 00106 fprintf(stderr, "Can't open X11 display %s\n", XDisplayName(display_name)); 00107 goto fail; 00108 } 00109 } 00110 int theScreen = DefaultScreen(dpy); 00111 scrn = ScreenOfDisplay(dpy, theScreen); 00112 dispdepth = DefaultDepth(dpy, theScreen); 00113 XVisualInfo vinfo; 00114 if (!( (dispdepth >= 15 && dispdepth <= 32 && XMatchVisualInfo(dpy, theScreen, dispdepth, TrueColor, &vinfo) ) 00115 || XMatchVisualInfo(dpy, theScreen, 24, TrueColor, &vinfo) 00116 || XMatchVisualInfo(dpy, theScreen, 32, TrueColor, &vinfo) 00117 || XMatchVisualInfo(dpy, theScreen, 16, TrueColor, &vinfo) 00118 || XMatchVisualInfo(dpy, theScreen, 15, TrueColor, &vinfo) 00119 )) { 00120 fprintf(stderr, "Display has no appropriate True Color visual\n"); 00121 goto fail; 00122 } 00123 vis = vinfo.visual; 00124 depth = dispdepth = vinfo.depth; 00125 mask2bits(vinfo.red_mask, red_mask, red_shift); 00126 mask2bits(vinfo.green_mask, green_mask, green_shift); 00127 mask2bits(vinfo.blue_mask, blue_mask, blue_shift); 00128 rootW = RootWindow(dpy, theScreen); 00129 cmap = XCreateColormap(dpy, rootW, vis, AllocNone); 00130 XSetWindowAttributes attrs; 00131 attrs.backing_store = Always; 00132 attrs.colormap = cmap; 00133 attrs.event_mask = StructureNotifyMask|KeyPressMask|ButtonPressMask|ButtonReleaseMask; 00134 attrs.background_pixel = BlackPixelOfScreen(scrn); 00135 attrs.border_pixel = WhitePixelOfScreen(scrn); 00136 win = XCreateWindow(dpy, rootW, 00137 0, 0, xsize, ysize, 2, 00138 dispdepth, InputOutput, vis, 00139 CWBackingStore | CWColormap | CWEventMask | 00140 CWBackPixel | CWBorderPixel, 00141 &attrs); 00142 if(!win) { 00143 fprintf(stderr, "Can't create the window\n"); 00144 goto fail; 00145 } 00146 XSizeHints sh; 00147 sh.flags = PSize | PMinSize | PMaxSize; 00148 sh.width = sh.min_width = sh.max_width = xsize; 00149 sh.height = sh.min_height = sh.max_height = ysize; 00150 XSetStandardProperties( dpy, win, g_video->title, g_video->title, None, NULL, 0, &sh ); 00151 _XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", false); 00152 XSetWMProtocols(dpy, win, &_XA_WM_DELETE_WINDOW, 1); 00153 gc = XCreateGC(dpy, win, 0L, &xgcv); 00154 XMapRaised(dpy, win); 00155 XFlush(dpy); 00156 #ifdef X_FULLSYNC 00157 XSynchronize(dpy, true); 00158 #endif 00159 XSetErrorHandler(xerr_handler); 00160 00161 int imgbytes = xsize*ysize*(dispdepth<=16?2:4); 00162 const char *vidstr; 00163 #ifndef X_NOSHMEM 00164 int major, minor, pixmaps; 00165 if(XShmQueryExtension(dpy) && 00166 XShmQueryVersion(dpy, &major, &minor, &pixmaps)) 00167 { // Shared memory 00168 shmseginfo.shmid = shmget(IPC_PRIVATE, imgbytes, IPC_CREAT|0777); 00169 if(shmseginfo.shmid < 0) { 00170 fprintf(stderr, "Warning: Can't get shared memory: %s\n", strerror(errno)); 00171 goto generic; 00172 } 00173 g_pImg = (unsigned int*)(shmseginfo.shmaddr = (char*)shmat(shmseginfo.shmid, 0, 0)); 00174 if(g_pImg == (unsigned int*)-1) { 00175 fprintf(stderr, "Warning: Can't attach to shared memory: %s\n", strerror(errno)); 00176 shmctl(shmseginfo.shmid, IPC_RMID, NULL); 00177 goto generic; 00178 } 00179 shmseginfo.readOnly = false; 00180 if(!XShmAttach(dpy, &shmseginfo) || x_error) { 00181 char err[256]; XGetErrorText(dpy, x_error, err, 255); 00182 fprintf(stderr, "Warning: Can't attach shared memory to display: %s (%d)\n", err, x_error); 00183 shmdt(shmseginfo.shmaddr); shmctl(shmseginfo.shmid, IPC_RMID, NULL); 00184 goto generic; 00185 } 00186 00187 #ifndef X_NOSHMPIX 00188 if(pixmaps && XShmPixmapFormat(dpy) == ZPixmap) 00189 { // Pixmaps 00190 vidtype = 2; vidstr = "X11 shared memory pixmap"; 00191 pixmap = XShmCreatePixmap(dpy, win, (char*)g_pImg, &shmseginfo, xsize, ysize, dispdepth); 00192 XSetWindowBackgroundPixmap(dpy, win, pixmap); 00193 } else 00194 #endif//!X_NOSHMPIX 00195 { // Standart 00196 vidtype = 1; vidstr = "X11 shared memory"; 00197 ximage = XShmCreateImage(dpy, vis, dispdepth, 00198 ZPixmap, 0, &shmseginfo, xsize, ysize); 00199 if(!ximage) { 00200 fprintf(stderr, "Can't create the shared image\n"); 00201 goto fail; 00202 } 00203 assert(ximage->bytes_per_line == xsize*(dispdepth<=16?2:4)); 00204 ximage->data = shmseginfo.shmaddr; 00205 } 00206 } else 00207 #endif 00208 { 00209 generic: 00210 vidtype = 0; vidstr = "generic X11"; 00211 g_pImg = new unsigned int[imgbytes/sizeof(int)]; 00212 ximage = XCreateImage(dpy, vis, dispdepth, ZPixmap, 0, (char*)g_pImg, xsize, ysize, 32, imgbytes/ysize); 00213 if(!ximage) { 00214 fprintf(stderr, "Can't create the image\n"); 00215 goto fail; 00216 } 00217 } 00218 printf("Note: using %s with %s visual for %d-bit color depth\n", vidstr, vis==DefaultVisual(dpy, theScreen)?"default":"non-default", dispdepth); 00219 running = true; 00220 return true; 00221 } // end of enclosing local varables 00222 fail: 00223 terminate(); init_console(); 00224 return false; 00225 } 00226 00227 bool video::init_console() 00228 { 00229 if(!g_pImg && g_sizex && g_sizey) { 00230 dispdepth = 24; red_shift = 16; vidtype = 3; // fake video 00231 g_pImg = new unsigned int[g_sizex*g_sizey]; 00232 running = true; 00233 } 00234 return true; 00235 } 00236 00237 void video::terminate() 00238 { 00239 running = false; 00240 if(dpy) { 00241 vidtype = 3; // stop video 00242 if(threaded) { pthread_mutex_lock(&g_mutex); pthread_mutex_unlock(&g_mutex); } 00243 if(ximage) { XDestroyImage(ximage); ximage = 0; g_pImg = 0; } // it frees g_pImg for vidtype == 0 00244 #ifndef X_NOSHMEM 00245 if(pixmap) XFreePixmap(dpy, pixmap); 00246 if(shmseginfo.shmaddr) { XShmDetach(dpy, &shmseginfo); shmdt(shmseginfo.shmaddr); g_pImg = 0; } 00247 if(shmseginfo.shmid >= 0) shmctl(shmseginfo.shmid, IPC_RMID, NULL); 00248 #endif 00249 if(gc) XFreeGC(dpy, gc); 00250 if(win) XDestroyWindow(dpy, win); 00251 XCloseDisplay(dpy); dpy = 0; 00252 } 00253 if(g_pImg) { delete[] g_pImg; g_pImg = 0; } // if was allocated for console mode 00254 } 00255 00256 video::~video() 00257 { 00258 if(g_video) terminate(); 00259 g_video = 0; 00260 } 00261 00263 void video::main_loop() 00264 { 00265 struct timezone tz; gettimeofday(&g_time, &tz); 00266 on_process(); 00267 } 00268 00270 bool video::next_frame() 00271 { 00272 if(!running) return false; 00274 if(vidtype == 3 || threaded && pthread_mutex_trylock(&g_mutex)) 00275 return running; 00277 g_fps++; 00278 #ifndef X_NOSHMPIX 00279 if(vidtype == 2 && updating) XClearWindow(dpy, win); 00280 #endif 00281 while( XPending(dpy) ) { 00282 XEvent report; XNextEvent(dpy, &report); 00283 switch( report.type ) { 00284 case ClientMessage: 00285 if(report.xclient.format != 32 || report.xclient.data.l[0] != _XA_WM_DELETE_WINDOW) break; 00286 case DestroyNotify: 00287 running = false; 00288 case KeyPress: 00289 on_key( XLookupKeysym(&report.xkey, 0) ); break; 00290 case ButtonPress: 00291 on_mouse( report.xbutton.x, report.xbutton.y, report.xbutton.button ); break; 00292 case ButtonRelease: 00293 on_mouse( report.xbutton.x, report.xbutton.y, -report.xbutton.button ); break; 00294 } 00295 } 00296 struct timezone tz; struct timeval now_time; gettimeofday(&now_time, &tz); 00297 double sec = (now_time.tv_sec+1.0*now_time.tv_usec/1000000.0) - (g_time.tv_sec+1.0*g_time.tv_usec/1000000.0); 00298 if(sec > 1) { 00299 memcpy(&g_time, &now_time, sizeof(g_time)); 00300 if(calc_fps) { 00301 double fps = g_fps; g_fps = 0; 00302 char buffer[256]; snprintf(buffer, 256, "%s%s: %d fps", title, updating?"":" (no updating)", int(fps/sec)); 00303 XStoreName(dpy, win, buffer); 00304 } 00305 #ifndef X_FULLSYNC 00306 XSync(dpy, false); // It is often better then using XSynchronize(dpy, true) 00307 #endif//X_FULLSYNC 00308 } 00309 if(threaded) pthread_mutex_unlock(&g_mutex); 00310 return true; 00311 } 00312 00314 void video::show_title() 00315 { 00316 if(vidtype < 3) 00317 XStoreName(dpy, win, title); 00318 } 00319 00320 drawing_area::drawing_area(int x, int y, int sizex, int sizey) 00321 : start_x(x), start_y(y), size_x(sizex), size_y(sizey), pixel_depth(dispdepth), 00322 base_index(y*g_sizex + x), max_index(g_sizex*g_sizey), index_stride(g_sizex), ptr32(g_pImg) 00323 { 00324 assert(x < g_sizex); assert(y < g_sizey); 00325 assert(x+sizex <= g_sizex); assert(y+sizey <= g_sizey); 00326 00327 index = base_index; // current index 00328 } 00329 00330 drawing_area::~drawing_area() 00331 { 00332 if(!g_video->updating) return; 00333 #ifndef X_NOSHMEM 00334 switch(vidtype) { 00335 case 0: 00336 #endif 00337 pthread_mutex_lock(&g_mutex); 00338 if(vidtype == 0) XPutImage(dpy, win, gc, ximage, start_x, start_y, start_x, start_y, size_x, size_y); 00339 pthread_mutex_unlock(&g_mutex); 00340 #ifndef X_NOSHMEM 00341 break; 00342 case 1: 00343 pthread_mutex_lock(&g_mutex); 00344 if(vidtype == 1) XShmPutImage(dpy, win, gc, ximage, start_x, start_y, start_x, start_y, size_x, size_y, false); 00345 pthread_mutex_unlock(&g_mutex); 00346 break; 00347 /*case 2: make it in next_frame(); break;*/ 00348 } 00349 #endif 00350 }
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.