#include "pointer.h" #include "stipple.h" #ifndef _xsound_h # include "xsound.h" #endif #ifndef _game_h # include "game.h" #endif #ifndef _rgb_h # include "rgb.h" #endif #include Display *dpy; // the display connection int scr; // default screen of the display Window win; // the output window Window new_root=0; // a surrounding black window, when started with option -root (default) Colormap cmap; // the colormap used for the window Colormap local_cmap; // flag, if the colormap had to be created local static int nbg_cols_all; static int bg_unused; static int nball_cols_to_alloc; Pixmap pointer_pmap; // Pixmap (wird vom PBall benutzt) int pointer_off_x, pointer_off_y; static Pixmap stipple_pmap=0; // The stipple cache is used to store the 'textured' pixmap to // reuse some on several output-operation. #define STIPPLE_CACHE 10 static const int stipple_sz=128; static Pixmap rand_stipple[STIPPLE_CACHE]; static long rand_col[STIPPLE_CACHE]; static unsigned long start_seconds; static int info_ch = 0; #ifdef STATISTICS static GC gc_text; static int info_cw = 0; static XFontStruct *fs = 0; static Font info_font; static unsigned long info_fg, info_bg; static const int info_width = 16; static int info_offset = 0; void showinfo( StatType stat, const char *info ) { static info_toggle=0; if (new_root) { int len = strlen(info); if (stat==OffsetInfo) { if (len) { info_toggle^=1; if (info_toggle) { XSetForeground( dpy, gc_text, info_bg ); XSetBackground( dpy, gc_text, info_fg ); } } else { info = " "; len = 20; } } XDrawImageString( dpy, new_root, gc_text, info_offset - (stat+1)*info_width*info_cw, DisplayHeight(dpy,scr)- 1, info, len); if ((stat==OffsetInfo) && (info_toggle)) { XSetForeground( dpy, gc_text, info_fg ); XSetBackground( dpy, gc_text, info_bg ); } } } #define GRAPH_SIZE_X 50 #define GRAPH_SIZE_Y 800 void graphinfo( int value ) { static int row=-1; if (row<0) { for (row=0;row<=GRAPH_SIZE_Y;row+=20) { for (int i=0;i<=100;i+=20) { XDrawPoint(dpy,new_root,gc_text,row,DisplayHeight(dpy,scr)-1-i ); } } row=0; } if (value>120) value=120; XSetForeground( dpy, gc_text, info_bg ); XDrawLine(dpy, new_root, gc_text, row, DisplayHeight(dpy,scr)-1, row, DisplayHeight(dpy,scr)-1-GRAPH_SIZE_X); XSetForeground( dpy, gc_text, info_fg ); if (row%20==0) { for (int i=0;i<=100;i+=20) { XDrawPoint(dpy, new_root, gc_text, row, DisplayHeight(dpy,scr)-1-i ); } } XDrawLine(dpy, new_root, gc_text, row, DisplayHeight(dpy,scr)-1-value+1, row, DisplayHeight(dpy,scr)-1-value-1); row++; if (row>GRAPH_SIZE_Y) row=0; XDrawLine(dpy, new_root, gc_text, row, DisplayHeight(dpy,scr)-1, row, DisplayHeight(dpy,scr)-11); } #endif static void InitTime() { struct timeval start; X_GETTIMEOFDAY( &start ); // comes with X11R6 (see stdinc.h) start_seconds = start.tv_sec; } double GetCurrentTime() { struct timeval current; X_GETTIMEOFDAY( ¤t ); // comes with X11R6 (see stdinc.h) return( ((double)(current.tv_sec-start_seconds))+(current.tv_usec/1000000.0) ); } GC gc_default; GC gc_lay1; GC gc_lay2; GC gc_cursor; GC gc_current; GC gc_bxor; GC gc_bclear; GC gc_ballwhite; GC gc_ball[MAX_BALL]; void SetBgColor( ColorId col ) { gc_current = gc_default; // // set the foreground pixel // if (col&BG_MASK) { XSetForeground( dpy, gc_current, ball_pix[0]|bg_pix[col&COLOR_MASK] ); } else if (col&STAT_MASK) { XSetForeground( dpy, gc_current, stat_pix[col&COLOR_MASK] ); } else { XSetForeground( dpy, gc_current, ball_pix[col&COLOR_MASK] ); } // // set background (when in mixed mode) // if (col&MIX_MASK) { // // set background color // if ((col>>COLOR_BITS)&BG_MASK) { XSetBackground( dpy, gc_current, ball_pix[0]|bg_pix[(col>>COLOR_BITS)&COLOR_MASK] ); } else if ((col>>COLOR_BITS)&STAT_MASK) { XSetBackground(dpy,gc_current,stat_pix[(col>>COLOR_BITS)&COLOR_MASK]); } else { XSetBackground(dpy,gc_current,ball_pix[(col>>COLOR_BITS)&COLOR_MASK]); } // // set (or create) background stipple // if (col&RAND_MASK) { int i; for (i=0;i>RAND_SHIFT)+1); j>0;j--) { XDrawPoint(dpy,rand_stipple[i],gc,rand()%stipple_sz,rand()%stipple_sz); } XFreeGC(dpy,gc); } XSetStipple( dpy, gc_current, rand_stipple[i] ); } else { XSetStipple( dpy, gc_current, stipple_pmap ); } XSetFillStyle( dpy, gc_current, FillOpaqueStippled ); } else { XSetFillStyle( dpy, gc_current, FillSolid ); } } int ParseColor( const char *name, XColor *col ) { RGBColor rgbcol; if ( rgbcol.SetColor(name)==0 ) { col->red = rgbcol.red | (rgbcol.red <<8); col->green = rgbcol.green | (rgbcol.green<<8); col->blue = rgbcol.blue | (rgbcol.blue <<8); // printf("'%s': %04x/%04x/%04x\n",name,col->red,col->green,col->blue); return 0; } if (XParseColor(dpy,cmap,name,col)) return 0; else { fprintf(stderr,"failed to query RGB-values for '%s'\n",name ); return -1; } } int StoreColor( unsigned pixel ) { long stat=-1; unsigned long bgc; int nbgc; unsigned long shc; int nshc; unsigned long cuc; unsigned long bc; int nbc; bgc = pixel&bg_mask; // Hintergrund for (nbgc=(nbg_cols_all-1)-1;nbgc>=0;nbgc--) {// passenden Index suchen if (bg_pix[nbgc]==bgc) break; } if ((bgc)&&nbgc>=nbg_cols) { stat = nbgc-nbg_cols; // unbenutztes Pixel -> static } shc = pixel&shade_mask; // Schattierung for (nshc=0;nshc=nshade_cols) { printf( "not implemented: shaded %d free for static\n", pixel ); return -1; // unbenutztes Pixel } cuc = pixel&cursor_mask; // Cursor bc = pixel-bgc-shc-cuc; // Ballfarbe for (nbc=0;nbc=nball_cols_to_alloc) return -1; if (nbc>=nball_cols) { stat = nball_cols*bg_unused + (nbc-nball_cols)*(nbg_cols_all) + ((nbgc>=0)?nbgc+1:0); } else { if (stat>=0) stat+=(nbc*bg_unused); } XColor col; if (cuc&&(stat=0) { if (stat>=1; } nbg_cols_all = (1<>=1; } if (cursor_col) nplanes++; // // Anfordern der Farben // DBG1( ShowColors, "Graphic: %d planes\n", nplanes ); DBG1( ShowColors, "Graphic: %d ball colors\n", nball_cols ); DBG1( ShowColors, "Graphic: %d static colors\n", nstat_cols ); while (nstat_cols>nball_cols*bg_unused +(nball_cols_to_alloc-nball_cols)*(nbg_cols_all)) { nball_cols_to_alloc++; } DBG1( ShowColors, "Graphic: %d statics 'between planes'\n", nball_cols*bg_unused ); DBG1( ShowColors, "Graphic: allocating %d ball colors\n", nball_cols_to_alloc ); cmap = DefaultColormap( dpy, scr ); if (XAllocColorCells( dpy, cmap, False, plane_mask, nplanes, ball_pix, nball_cols_to_alloc )==0) { DBG0( UnixTrace, "Allocation of colors failed - creating local colormap.\n" ); cmap= XCreateColormap(dpy,win,DefaultVisual(dpy,scr),AllocNone); if (XAllocColorCells( dpy, cmap, False, plane_mask, nplanes, ball_pix, nball_cols_to_alloc )==0) { fprintf(stderr, "not enough colors: " ); fprintf(stderr, "I need %d colors + %d planes.\n", nball_cols_to_alloc, nplanes ); exit(0); } if (new_root) { XSetWindowAttributes attrib; attrib.colormap = cmap; XChangeWindowAttributes( dpy, new_root, CWColormap, &attrib ); XSetWindowColormap( dpy, new_root, cmap ); } else { XSetWindowAttributes attrib; attrib.colormap = cmap; XChangeWindowAttributes( dpy, win, CWColormap, &attrib ); XSetWindowColormap( dpy, win, cmap ); } XSync(dpy,0); } // // Verteilen der Planes auf die Farben // int c=0; for (n=0;n>=1; } for (n=0;n>=1; } if (cursor_col) { cursor_mask = plane_mask[c]; } ball_mask=0; for (n=0;n>COLOR_BITS)&COLOR_MASK]; values.fill_style = FillOpaqueStippled; } else { values.fill_style = FillSolid; } gc_ball[i]=XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values ); } // // Pixmaps erzeugen // pointer_pmap = XCreatePixmapFromBitmapData(dpy,win, pointer_bits, pointer_width, pointer_height, cursor_mask, 0, DefaultDepth(dpy,scr) ); pointer_off_x = pointer_x_hot; pointer_off_y = pointer_y_hot; #ifdef DEBUG if (debug&Sync) { XSynchronize(dpy,1); } if ((debug&ShowSubWindow)&&(!new_root)) { XSizeHints hints; hints.flags = PPosition | PSize | PAspect | PMinSize | PMaxSize; hints.x = (DisplayWidth(dpy,scr) -max_x)/2; hints.y = 0; hints.width = hints.min_width = hints.max_width = max_x; hints.height = hints.min_height = hints.max_height = max_y; XSetWMNormalHints( dpy,win,&hints ); } #endif #ifdef DEBUG if (debug&ShowColors) { Window help; const int lpixs_x = 16; const int lpixs_y = 16; const int d=16; const int o=2; // To overcome a bug? in the fvwm window-manager, the server is now // synchronized and a pause for a second is taken. I wonder what fvwm // is doing in that second ... XSync(dpy,0); printf( "wait a second, so that even the FVWM gets a change for not crashing\n" ); sleep(1); help = CreateWindow("Noname",lpixs_x*(d+o)+1 ,lpixs_y*(d+o)+1); for (int px=0;pxfid; info_cw = XTextWidth(fs,"A",1); info_ch = fs->ascent + fs->descent; } #endif // // Größe des Fensters bestimmen: Fenster zentrieren // int dp_height = DisplayHeight(dpy,scr)-info_ch; world_x = x; world_y = y; if ( size>0 ) { if (size>DisplayWidth(dpy,scr)) size = DisplayWidth(dpy,scr); max_x = size; max_y = (int)(size/world_x*world_y); if (max_y>dp_height) { max_y = dp_height; size = max_x = (int)(max_y/world_y*world_x); } } else if ( ((double)DisplayWidth(dpy,scr))/dp_height < world_x/world_y ) { max_x = DisplayWidth(dpy,scr); max_y = (int)(max_x/world_x*world_y); } else { max_y = dp_height; max_x = (int)(max_y/world_y*world_x); } // if ( size<=0 ) { setwinattr.override_redirect = (no_override)?False:True; new_root = XCreateSimpleWindow( dpy, RootWindow( dpy, scr ), 0, 0, DisplayWidth( dpy,scr ), DisplayHeight( dpy,scr ), 0, WhitePixel( dpy,scr ), BlackPixel( dpy,scr ) ); XChangeWindowAttributes( dpy, new_root, CWOverrideRedirect, &setwinattr ); win = XCreateSimpleWindow( dpy, new_root, (DisplayWidth( dpy,scr )-max_x)/2, (dp_height-max_y)/2, max_x, max_y, 0, BlackPixel( dpy,scr ),WhitePixel( dpy,scr ) ); XSelectInput( dpy, new_root, ColormapChangeMask|FocusChangeMask|KeyPressMask ); XSelectInput( dpy, win, ExposureMask|KeyPressMask ); setwinattr.backing_store = (0)?Always:NotUseful; setwinattr.bit_gravity = ForgetGravity;; XChangeWindowAttributes(dpy,win,CWBitGravity|CWBackingStore,&setwinattr ); w2n = (max_x-2)/world_x; } else { new_root = 0; win = XCreateSimpleWindow( dpy, RootWindow( dpy, scr ), 0,0 , max_x, max_y, 2, 0,0 ); XSelectInput( dpy, win, KeyPressMask|ExposureMask); setwinattr.backing_store = (0)?Always:NotUseful; setwinattr.bit_gravity = ForgetGravity;; XChangeWindowAttributes(dpy,win,CWBitGravity|CWBackingStore,&setwinattr ); w2n = (max_x-2)/world_x; } // // BellPitch einstellen // XStoreName( dpy, win, "flying" ); InitTime(); // Initialisierung der Zeitmessung } void UnlockGraphic() { XUngrabServer(dpy); XSync(dpy,0); no_server_grabs+=100; } void CloseGraphic() { int i; #ifdef STATISTICS if (fs) XFreeFont(dpy,fs); #endif for (i=0;iExposeRedraw(); PBallTop::ForAll( &PBallTop::Redraw ); break; } case ColormapNotify: while( XCheckMaskEvent( dpy, ColormapChangeMask, &event )); if (event.xcolormap.state!=ColormapInstalled && event.xcolormap.colormap==cmap) { printf( "### colormap was uninstalled by window manager\n" ); if (no_server_grabs) { printf( " please let me grab the server or try the option -no_override\n" ); exit(0); } else { printf( " I AM GRABBING THE SERVER NOW ...\n" ); } XGrabServer(dpy); XInstallColormap(dpy,cmap); no_server_grabs-=100; } break; case FocusIn: // printf( "focus: In\n" ); break; case FocusOut: // printf( "focus: Out\n" ); break; default: break; } } return 0; } #define XPix(x) ((int)((x)*w2n)) #define YPix(y) ((int)((y)*w2n)) #define Pix(r) ((int)((r)*w2n)) void DrawLine( const Real& x1, const Real& y1, const Real& x2, const Real& y2 ) { int px1 = XPix(x1); int py1 = YPix(y1); int px2 = XPix(x2); int py2 = YPix(y2); XDrawLine( dpy, win, gc_current, px1, py1, px2, py2 ); } void DrawArc( const Real& x, const Real& y, const Real& r, const Real& from, const Real& angle ) { int px = XPix(x-r); int py = YPix(y-r); int size= Pix(2.*r); XDrawArc( dpy, win, gc_current, px, py, size, size, (int)(from*64.), (int)(angle*64.) ); } void DrawCircle( const Real& x, const Real& y, const Real& r ) { int px = XPix(x-r); int py = YPix(y-r); int size= Pix(2.*r); XDrawArc( dpy, win, gc_current, px, py, size, size, 0, (int)360*64 ); } void FillArc( const Real& x, const Real& y, const Real& r, const Real& from, const Real& angle ) { int px = XPix(x-r); int py = YPix(y-r); int size= Pix(2.*r); XFillArc( dpy, win, gc_current, px, py, size, size, (int)(from*64.), (int)(angle*64.) ); } void FillCircle( const Real& x, const Real& y, const Real& r ) { int px = XPix(x-r); int py = YPix(y-r); int size= Pix(2.*r); XFillArc( dpy, win, gc_current, px, py, size, size, 0, (int)360*64 ); } void FillRectangle( const Real& x, const Real& y, const Real& width, const Real& height ) { int px1 = XPix(x); int py1 = YPix(y); int px2 = XPix(x+width); int py2 = YPix(y+height); XFillRectangle( dpy, win, gc_current, px1, py1, px2-px1, py2-py1 ); } void FillPoly( int n, ... ) { va_list argptr; Vec2 *v; int i; XPoint buffer[10]; XPoint *p; // Zeiger auf Puffer, um gegebenenfalls mehr anzufordern va_start(argptr,n); if (sizeof(buffer)/sizeof(XPoint)<(unsigned)n) p=new XPoint[n]; else p=buffer; for (i=0;iX()); p[i].y = YPix(v->Y()); } XFillPolygon( dpy,win,gc_current,p,n,0,0); if (p!=buffer) delete p; va_end(argptr); } void FillPoly( int n, Vec2 v[] ) { int i; XPoint buffer[10]; XPoint *p; if (sizeof(buffer)/sizeof(XPoint)<(unsigned)n) p=new XPoint[n]; else p=buffer; for (i=0;i