/* A simple graphics library for CSE 20211 by Douglas Thain This work is licensed under a Creative Commons Attribution 4.0 International License. https://creativecommons.org/licenses/by/4.0/ For complete documentation, see: http://www.nd.edu/~dthain/courses/cse20211/fall2013/gfx Version 3, 11/07/2012 - Now much faster at changing colors rapidly. Version 2, 9/23/2011 - Fixes a bug that could result in jerky animation. */ #include #include #include #include #include "gfx.h" /* gfx_open creates several X11 objects, and stores them in globals for use by the other functions in the library. */ static Display *gfx_display=0; static Window gfx_window; static GC gfx_gc; static Colormap gfx_colormap; static int gfx_fast_color_mode = 0; /* These values are saved by gfx_wait then retrieved later by gfx_xpos and gfx_ypos. */ static int saved_xpos = 0; static int saved_ypos = 0; /* Open a new graphics window. */ void gfx_open( int width, int height, const char *title ) { gfx_display = XOpenDisplay(0); if(!gfx_display) { fprintf(stderr,"gfx_open: unable to open the graphics window.\n"); exit(1); } Visual *visual = DefaultVisual(gfx_display,0); if(visual && visual->class==TrueColor) { gfx_fast_color_mode = 1; } else { gfx_fast_color_mode = 0; } int blackColor = BlackPixel(gfx_display, DefaultScreen(gfx_display)); int whiteColor = WhitePixel(gfx_display, DefaultScreen(gfx_display)); gfx_window = XCreateSimpleWindow(gfx_display, DefaultRootWindow(gfx_display), 0, 0, width, height, 0, blackColor, blackColor); XSetWindowAttributes attr; attr.backing_store = Always; XChangeWindowAttributes(gfx_display,gfx_window,CWBackingStore,&attr); XStoreName(gfx_display,gfx_window,title); XSelectInput(gfx_display, gfx_window, StructureNotifyMask|KeyPressMask|ButtonPressMask); XMapWindow(gfx_display,gfx_window); gfx_gc = XCreateGC(gfx_display, gfx_window, 0, 0); gfx_colormap = DefaultColormap(gfx_display,0); XSetForeground(gfx_display, gfx_gc, whiteColor); // Wait for the MapNotify event for(;;) { XEvent e; XNextEvent(gfx_display, &e); if (e.type == MapNotify) break; } } /* Draw a single point at (x,y) */ void gfx_point( int x, int y ) { XDrawPoint(gfx_display,gfx_window,gfx_gc,x,y); } /* Draw a line from (x1,y1) to (x2,y2) */ void gfx_line( int x1, int y1, int x2, int y2 ) { XDrawLine(gfx_display,gfx_window,gfx_gc,x1,y1,x2,y2); } /* Change the current drawing color. */ void gfx_color( int r, int g, int b ) { XColor color; if(gfx_fast_color_mode) { /* If this is a truecolor display, we can just pick the color directly. */ color.pixel = ((b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16) ); } else { /* Otherwise, we have to allocate it from the colormap of the display. */ color.pixel = 0; color.red = r<<8; color.green = g<<8; color.blue = b<<8; XAllocColor(gfx_display,gfx_colormap,&color); } XSetForeground(gfx_display, gfx_gc, color.pixel); } /* Clear the graphics window to the background color. */ void gfx_clear() { XClearWindow(gfx_display,gfx_window); } /* Change the current background color. */ void gfx_clear_color( int r, int g, int b ) { XColor color; color.pixel = 0; color.red = r<<8; color.green = g<<8; color.blue = b<<8; XAllocColor(gfx_display,gfx_colormap,&color); XSetWindowAttributes attr; attr.background_pixel = color.pixel; XChangeWindowAttributes(gfx_display,gfx_window,CWBackPixel,&attr); } int gfx_event_waiting() { XEvent event; gfx_flush(); while (1) { if(XCheckMaskEvent(gfx_display,-1,&event)) { if(event.type==KeyPress) { XPutBackEvent(gfx_display,&event); return 1; } else if (event.type==ButtonPress) { XPutBackEvent(gfx_display,&event); return 1; } else { return 0; } } else { return 0; } } } /* Wait for the user to press a key or mouse button. */ char gfx_wait() { XEvent event; gfx_flush(); while(1) { XNextEvent(gfx_display,&event); if(event.type==KeyPress) { saved_xpos = event.xkey.x; saved_ypos = event.xkey.y; return XLookupKeysym(&event.xkey,0); } else if(event.type==ButtonPress) { saved_xpos = event.xkey.x; saved_ypos = event.xkey.y; return event.xbutton.button; } } } /* Return the X and Y coordinates of the last event. */ int gfx_xpos() { return saved_xpos; } int gfx_ypos() { return saved_ypos; } /* Flush all previous output to the window. */ void gfx_flush() { XFlush(gfx_display); }