diff --git a/Lab3/Lab3 b/Lab3/Lab3 deleted file mode 100755 index ad3c598..0000000 Binary files a/Lab3/Lab3 and /dev/null differ diff --git a/Lab4/Lab4 b/Lab4/Lab4 new file mode 100755 index 0000000..4f3e1aa Binary files /dev/null and b/Lab4/Lab4 differ diff --git a/Lab4/drawbase.h b/Lab4/drawbase.h new file mode 100644 index 0000000..0a9d8fa --- /dev/null +++ b/Lab4/drawbase.h @@ -0,0 +1,21 @@ +#ifndef DRAWBASE_H +#define DRAWBASE_H + +// forward reference +class GraphicsContext; + +class DrawingBase +{ + public: + // prevent warnings + virtual ~DrawingBase(){} + virtual void paint(GraphicsContext* gc){} + virtual void keyDown(GraphicsContext* gc, unsigned int keycode){} + virtual void keyUp(GraphicsContext* gc, unsigned int keycode){} + virtual void mouseButtonDown(GraphicsContext* gc, + unsigned int button, int x, int y){} + virtual void mouseButtonUp(GraphicsContext* gc, + unsigned int button, int x, int y){} + virtual void mouseMove(GraphicsContext* gc, int x, int y){} +}; +#endif \ No newline at end of file diff --git a/Lab4/gcontext.cpp b/Lab4/gcontext.cpp new file mode 100644 index 0000000..b091b77 --- /dev/null +++ b/Lab4/gcontext.cpp @@ -0,0 +1,26 @@ +/* This is an abstract base class representing a generic graphics + * context. Most implementation specifics will need to be provided by + * a concrete implementation. See header file for specifics. */ + +#define _USE_MATH_DEFINES // for M_PI +#include // for trig functions +#include "gcontext.h" + +/* + * Destructor - does nothing + */ +GraphicsContext::~GraphicsContext() +{ + // nothing to do + // here to insure subclasses handle destruction properly +} + +//does nothing +void GraphicsContext::drawLine(int x0, int y0, int x1, int y1){} +void GraphicsContext::drawCircle(int x0, int y0, unsigned int radius){} + + +void GraphicsContext::endLoop() +{ + run = false; +} \ No newline at end of file diff --git a/Lab4/gcontext.h b/Lab4/gcontext.h new file mode 100644 index 0000000..61c6713 --- /dev/null +++ b/Lab4/gcontext.h @@ -0,0 +1,141 @@ +#ifndef GCONTEXT_H +#define GCONTEXT_H + +/** + * This class is intended to be the abstract base class + * for a graphical context for various platforms. Any + * concrete subclass will need to implement the pure virtual + * methods to support setting pixels, getting pixel color, + * setting the drawing mode, and running an event loop to + * capture mouse and keyboard events directed to the graphics + * context (or window). Specific expectations for the various + * methods are documented below. + * + * */ + + +// forward reference - needed because runLoop needs a target for events +class DrawingBase; + + +class GraphicsContext +{ + public: + /********************************************************* + * Some constants and enums + *********************************************************/ + // This enumerated type is an argument to setMode and allows + // us to support two different drawing modes. MODE_NORMAL is + // also call copy-mode and the affect pixel(s) are set to the + // color requested. XOR mode will XOR the new color with the + // existing color so that the change is reversible. + enum drawMode {MODE_NORMAL, MODE_XOR}; + + // Some colors - for fun + static const unsigned int BLACK = 0x000000; + static const unsigned int BLUE = 0x0000FF; + static const unsigned int GREEN = 0x00FF00; + static const unsigned int RED = 0xFF0000; + static const unsigned int CYAN = 0x00FFFF; + static const unsigned int MAGENTA = 0xFF00FF; + static const unsigned int YELLOW = 0xFFFF00; + static const unsigned int GRAY = 0x808080; + static const unsigned int WHITE = 0xFFFFFF; + + + /********************************************************* + * Construction / Destruction + *********************************************************/ + // Implementations of this class should include a constructor + // that creates the drawing canvas (window), sets a background + // color (which may be configurable), sets a default drawing + // color (which may be configurable), and start with normal + // (copy) drawing mode. + + // need a virtual destructor to ensure subclasses will have + // their destructors called properly. Must be virtual. + virtual ~GraphicsContext(); + + /********************************************************* + * Drawing operations + *********************************************************/ + + // Allows the drawing mode to be changed between normal (copy) + // and xor. The implementing context should default to normal. + virtual void setMode(drawMode newMode) = 0; + + // Set the current color. Implementations should default to white. + // color is 24-bit RGB value + virtual void setColor(unsigned int color) = 0; + + // Set pixel to the current color + virtual void setPixel(int x, int y) = 0; + + // Get 24-bit RGB pixel color at specified location + // unsigned int will likely be 32-bit on 32-bit systems, and + // possible 64-bit on some 64-bit systems. In either case, + // it is large enough to hold a 16-bit color. + virtual unsigned int getPixel(int x, int y) = 0; + + // This should reset entire context to the current background + virtual void clear()=0; + + // These are the naive implementations that use setPixel, + // but are overridable should a context have a better- + // performing version available. + + /* will need to be provided by the concrete + * implementation. + * + * Parameters: + * x0, y0 - origin of line + * x1, y1 - end of line + * + * Returns: void + */ + virtual void drawLine(int x0, int y0, int x1, int y1); + + /* will need to be provided by the concrete + * implementation. + * + * Parameters: + * x0, y0 - origin/center of circle + * radius - radius of circle + * + * Returns: void + */ + virtual void drawCircle(int x0, int y0, unsigned int radius); + + + /********************************************************* + * Event loop operations + *********************************************************/ + + // Run Event loop. This routine will receive events from + // the implementation and pass them along to the drawing. It + // will return when the window is closed or other implementation- + // specific sequence. + virtual void runLoop(DrawingBase* drawing) = 0; + + // This method will end the current loop if one is running + // a default version is supplied + virtual void endLoop(); + + + /********************************************************* + * Utility operations + *********************************************************/ + + // returns the width of the window + virtual int getWindowWidth() = 0; + + // returns the height of the window + virtual int getWindowHeight() = 0; + + protected: + // this flag is used to control whether the event loop + // continues to run. + bool run; +}; + +#endif \ No newline at end of file diff --git a/Lab4/main.cpp b/Lab4/main.cpp new file mode 100644 index 0000000..d7a712a --- /dev/null +++ b/Lab4/main.cpp @@ -0,0 +1,28 @@ +#include "x11context.h" +#include +#include + +int main(void) +{ + GraphicsContext* gc = new X11Context(800,600,GraphicsContext::BLACK); + + + // draw some lines + gc->setColor(GraphicsContext::GREEN); + gc->setPixel(10,10); + gc->setPixel(30,30); + gc->drawLine(100,100,500,500); + gc->setColor(GraphicsContext::RED); + gc->drawLine(100,500,500,500); + gc->setColor(GraphicsContext::BLUE); + gc->drawLine(500,500,500,100); + gc->setColor(GraphicsContext::YELLOW); + gc->drawLine(500,100,100,100); + gc->setColor(GraphicsContext::MAGENTA); + gc->drawCircle(300,300,200); + sleep(10); + + delete gc; + + return 0; +} \ No newline at end of file diff --git a/Lab4/makefile b/Lab4/makefile new file mode 100644 index 0000000..0de43e1 --- /dev/null +++ b/Lab4/makefile @@ -0,0 +1,25 @@ +# lab4 Makefile + +CC = g++ +CFLAGS = -c -MMD -g +LFLAGS = -lX11 +# Change w/ every new project +SOURCES = main.cpp gcontext.cpp x11context.cpp +OBJECTS = $(SOURCES:.cpp=.o) +# Change w/ every new project +EXECUTABLE = Lab4 + +all: $(EXECUTABLE) $(SOURCES) + +$(EXECUTABLE): $(OBJECTS) + $(CC) -o $@ $(OBJECTS) $(LFLAGS) + +-include *.d + +%.o:%.cpp + $(CC) $(CFLAGS) $< + +clean: + rm -f $(EXECUTABLE) + rm -f $(OBJECTS) + rm -f *.d \ No newline at end of file diff --git a/Lab4/x11context.cpp b/Lab4/x11context.cpp new file mode 100644 index 0000000..bc8f0d1 --- /dev/null +++ b/Lab4/x11context.cpp @@ -0,0 +1,239 @@ +/* Provides a simple drawing context for X11/XWindows + * You must have the X11 dev libraries installed. If missing, + * 'sudo apt-get install libx11-dev' should help. + */ + +#include // Every Xlib program must include this +#include // needed for XGetPixel +#include // needed for keyboard setup +#include "x11context.h" +#include "drawbase.h" +#include + +/** + * The only constructor provided. Allows size of window and background + * color be specified. + * */ +X11Context::X11Context(unsigned int sizex=400,unsigned int sizey=400, + unsigned int bg_color=GraphicsContext::BLACK) +{ + // Open the display + display = XOpenDisplay(NULL); + + // Holding a key in gives repeated key_press commands but only + // one key_release + int supported; + + XkbSetDetectableAutoRepeat(display,true,&supported); + + // Create a window - we will assume the color map is in RGB mode. + window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, + sizex, sizey, 0, 0 , bg_color); + + // Sign up for MapNotify events + XSelectInput(display, window, StructureNotifyMask); + + // Put the window on the screen + XMapWindow(display, window); + + // Create a "Graphics Context" + graphics_context = XCreateGC(display, window, 0, NULL); + + // Default color to white + XSetForeground(display, graphics_context, GraphicsContext::WHITE); + + // Wait for MapNotify event + for(;;) + { + XEvent e; + XNextEvent(display, &e); + if (e.type == MapNotify) + break; + } + + // We also want exposure, mouse, and keyboard events + XSelectInput(display, window, ExposureMask| + ButtonPressMask| + ButtonReleaseMask| + KeyPressMask| + KeyReleaseMask| + PointerMotionMask); + + // We need this to get the WM_DELETE_WINDOW message from the + // window manager in case user click the X icon + Atom atomKill = XInternAtom(display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(display, window, &atomKill, 1); + + return; +} + +// Destructor - shut down window and connection to server +X11Context::~X11Context() +{ + XFreeGC(display, graphics_context); + XDestroyWindow(display,window); + XCloseDisplay(display); +} + +// Set the drawing mode - argument is enumerated +void X11Context::setMode(drawMode newMode) +{ + if (newMode == GraphicsContext::MODE_NORMAL) + { + XSetFunction(display,graphics_context,GXcopy); + } + else + { + XSetFunction(display,graphics_context,GXxor); + } +} + +// Set drawing color - assume colormap is 24 bit RGB +void X11Context::setColor(unsigned int color) +{ + // Go ahead and set color here - better performance than setting + // on every setPixel + XSetForeground(display, graphics_context, color); +} + +// Set a pixel in the current color +void X11Context::setPixel(int x, int y) +{ + XDrawPoint(display, window, graphics_context, x, y); + XFlush(display); +} + +unsigned int X11Context::getPixel(int x, int y) +{ + XImage *image; + image = XGetImage (display, window, x, y, 1, 1, AllPlanes, XYPixmap); + XColor color; + color.pixel = XGetPixel (image, 0, 0); + XFree (image); + XQueryColor (display, DefaultColormap(display, DefaultScreen (display)), + &color); + // I now have RGB values, but, they are 16 bits each, I only want 8-bits + // each since I want a 24-bit RGB color value + unsigned int pixcolor = color.red & 0xff00; + pixcolor |= (color.green >> 8); + pixcolor <<= 8; + pixcolor |= (color.blue >> 8); + return pixcolor; +} + +void X11Context::clear() +{ + XClearWindow(display, window); + XFlush(display); +} + + + +// Run event loop +void X11Context::runLoop(DrawingBase* drawing) +{ + run = true; + + while(run) + { + XEvent e; + XNextEvent(display, &e); + + // Exposure event - lets not worry about region + if (e.type == Expose) + drawing->paint(this); + + // Key Down + else if (e.type == KeyPress) + drawing->keyDown(this,XLookupKeysym((XKeyEvent*)&e, + (((e.xkey.state&0x01)&&!(e.xkey.state&0x02))|| + (!(e.xkey.state&0x01)&&(e.xkey.state&0x02)))?1:0)); + + // Key Up + else if (e.type == KeyRelease){ + drawing->keyUp(this,XLookupKeysym((XKeyEvent*)&e, + (((e.xkey.state&0x01)&&!(e.xkey.state&0x02))|| + (!(e.xkey.state&0x01)&&(e.xkey.state&0x02)))?1:0)); + } + + // Mouse Button Down + else if (e.type == ButtonPress) + drawing->mouseButtonDown(this, + e.xbutton.button, + e.xbutton.x, + e.xbutton.y); + + // Mouse Button Up + else if (e.type == ButtonRelease) + drawing->mouseButtonUp(this, + e.xbutton.button, + e.xbutton.x, + e.xbutton.y); + + // Mouse Move + else if (e.type == MotionNotify) + drawing->mouseMove(this, + e.xmotion.x, + e.xmotion.y); + + // This will respond to the WM_DELETE_WINDOW from the + // window manager. + else if (e.type == ClientMessage) + break; + } +} + + +int X11Context::getWindowWidth() +{ + XWindowAttributes window_attributes; + XGetWindowAttributes(display,window, &window_attributes); + return window_attributes.width; +} + +int X11Context::getWindowHeight() +{ + XWindowAttributes window_attributes; + XGetWindowAttributes(display,window, &window_attributes); + return window_attributes.height; +} + +// void X11Context::drawLine(int x1, int y1, int x2, int y2) +// { +// XDrawLine(display, window, graphics_context, x1, y1, x2, y2); +// XFlush(display); +// } + +// Bresenham Implementation +void X11Context::drawLine(int x1, int y1, int x2, int y2){ + //setPixel(x1,y1); + // Check direction of line + if(abs(y2-y1) < abs(x2-x1)){ + if(x1 > x2){ + //swap + } else { + //swap + } + } else { + + } + int dx = x2-x1; + int dy = y2-y1; + int D = 2*dy-dx; + int y = y1; + for(int i = x1; i < x2; i++){ + setPixel(i,y); + if(D > 0){ + y = y+1; + D = D-2*dx; + } + D = D+2*dy; + } +} + +void X11Context::drawCircle(int x, int y, unsigned int radius) +{ + XDrawArc(display, window, graphics_context, x-radius, + y-radius, radius*2, radius*2, 0, 360*64); + XFlush(display); +} \ No newline at end of file diff --git a/Lab4/x11context.h b/Lab4/x11context.h new file mode 100644 index 0000000..54a7af1 --- /dev/null +++ b/Lab4/x11context.h @@ -0,0 +1,49 @@ +#ifndef X11_CONTEXT +#define X11_CONTEXT +/** + * This class is a sample implementation of the GraphicsContext class + * for the X11 / XWindows system. + * */ + +#include // Every Xlib program must include this +#include "gcontext.h" // base class + +class X11Context : public GraphicsContext +{ + public: + // Default Constructor + X11Context(unsigned int sizex,unsigned int sizey,unsigned int bg_color); + + // Destructor + virtual ~X11Context(); + + // Drawing Operations + void setMode(drawMode newMode); + void setColor(unsigned int color); + void setPixel(int x, int y); + unsigned int getPixel(int x, int y); + void clear(); + //void drawLine(int x1, int y1, int x2, int y2); + void drawLine(int x1, int y1, int x2, int y2); + void drawCircle(int x, int y, unsigned int radius); + + + // Event looop functions + void runLoop(DrawingBase* drawing); + + // we will use endLoop provided by base class + + // Utility functions + int getWindowWidth(); + int getWindowHeight(); + + + private: + // X11 stuff - specific to this context + Display* display; + Window window; + GC graphics_context; + +}; + +#endif \ No newline at end of file