Shadowrun: Awakened 29 September 2011 - Build 871
xvideo.cpp
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net