diff --git a/Lab6/drawbase.h b/Lab6/drawbase.h new file mode 100644 index 0000000..0a9d8fa --- /dev/null +++ b/Lab6/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/Lab6/gcontext.cpp b/Lab6/gcontext.cpp new file mode 100644 index 0000000..b091b77 --- /dev/null +++ b/Lab6/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/Lab6/gcontext.h b/Lab6/gcontext.h new file mode 100644 index 0000000..61c6713 --- /dev/null +++ b/Lab6/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/Lab6/image.cpp b/Lab6/image.cpp new file mode 100644 index 0000000..dcbdac2 --- /dev/null +++ b/Lab6/image.cpp @@ -0,0 +1,164 @@ +/** + * @file image.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-19 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "image.h" +#include +#include + +Image::Image(){ + shapes.clear(); +} + +Image::Image(const Image& from){ + for(int i = 0; i < from.shapes.size(); i++){ + shapes.push_back(from.shapes[i]->clone()); + } +} + +Image::~Image(){ + for(int i = 0; i < shapes.size(); i++){ + delete shapes[i]; + } + shapes.clear(); +} + +Image &Image::operator=(const Image& rhs){ + if(this != &rhs){ + for(int i = 0; i < shapes.size(); i++){ + delete shapes[i]; + } + shapes.clear(); + for(int i = 0; i < rhs.shapes.size(); i++){ + shapes.push_back(rhs.shapes[i]->clone()); + } + } + return *this; +} + +void Image::add(Shape* shape){ + shapes.push_back(shape->clone()); +} + +void Image::draw(GraphicsContext* gc, const ViewContext* vc){ + for(int i = 0; i < shapes.size(); i++){ + shapes[i]->draw(gc,vc); + } +} + +void Image::out(std::ostream& os){ + for(int i = 0; i < shapes.size(); i++){ + shapes[i]->out(os); + os << endl; + } +} + +void Image::in(std::istream& is){ + string line; + string token; + int shapeCoords[3][3]; + getline(is, line); + istringstream lineStream(line); + do{ + lineStream >> token; + switch(token[0]){ + case 'L': + { + // Next Line + getline(is, line); + lineStream.str(line); + lineStream.clear(); + // Iterate past "Color:" + lineStream >> token; + // Get actual color code + lineStream >> token; + stringstream hexColor(token); + // Convert hex code to unsigned int + uint32_t color; + hexColor >> hex >> color; + // hexColor >> color; + // Points + for(int i = 0; i < 2; i++){ + getline(is, line); + lineStream.str(line); + lineStream.clear(); + // Iterate past "P#:" + lineStream >> token; + // Get each coord + for(int j = 0; j < 3; j++){ + lineStream >> token; + shapeCoords[i][j] = stoi(token); + } + } + shapes.push_back( + new Line(shapeCoords[0][0],shapeCoords[0][1], + shapeCoords[1][0],shapeCoords[1][1],color) + ); + break; + } + case 'T': + { + // Next Line + getline(is, line); + lineStream.str(line); + lineStream.clear(); + // Iterate past "Color:" + lineStream >> token; + // Get actual color code + lineStream >> token; + stringstream hexColor(token); + // Convert hex code to unsigned int + uint32_t color; + hexColor >> hex >> color; + // hexColor >> color; + // Points + for(int i = 0; i < 3; i++){ + getline(is, line); + lineStream.str(line); + lineStream.clear(); + // Iterate past "P#:" + lineStream >> token; + // Get each coord + for(int j = 0; j < 3; j++){ + lineStream >> token; + shapeCoords[i][j] = stoi(token); + } + } + shapes.push_back( + new Triangle(shapeCoords[0][0],shapeCoords[0][1], + shapeCoords[1][0],shapeCoords[1][1], + shapeCoords[2][0],shapeCoords[2][1],color) + ); + break; + } + default: + { + cout << "Invalid Shape"; + } + + } + // Go to blank line + getline(is, line); + lineStream.str(line); + lineStream.clear(); + // Get next line + getline(is, line); + lineStream.str(line); + lineStream.clear(); + lineStream >> token; + } while(!is.eof()); // Loop until end of file +} + +void Image::erase(){ + for(int i = 0; i < shapes.size(); i++){ + delete shapes[i]; + } + shapes.clear(); +} \ No newline at end of file diff --git a/Lab6/image.h b/Lab6/image.h new file mode 100644 index 0000000..075e995 --- /dev/null +++ b/Lab6/image.h @@ -0,0 +1,54 @@ +#ifndef image_h +#define image_h +/** + * @file image.h + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-19 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include +#include "line.h" +#include "triangle.h" +using namespace std; + +class Shape; + +class Image{ + public: + // Image constructor + Image(); + + // Image copy constructor + Image(const Image& from); + + // Image destructor + ~Image(); + + // Image assignment operator + Image& operator=(const Image& rhs); + + // Adds a passed in shape to the image + void add(Shape* shape); + + // Draws all the shapes in the image + void draw(GraphicsContext* gc, const ViewContext* vc); + + // Outputs all of the shape data to an output stream + void out(std::ostream& os); + + // Inputs all the shape data from a given input stream + void in(std::istream& is); + + // Erases all the shapes in the image + void erase(); + + private: + vector shapes; +}; + +#endif \ No newline at end of file diff --git a/Lab6/line.cpp b/Lab6/line.cpp new file mode 100644 index 0000000..82bce05 --- /dev/null +++ b/Lab6/line.cpp @@ -0,0 +1,87 @@ +/** + * @file line.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-12 + * + * @copyright Copyright (c) 2022 + * + */ +#include "line.h" +#include + +Line::Line(int x0, int y0, int x1, int y1, uint32_t color){ + coords = new Matrix(3, 3); + + // Point 1 + (*coords)[0][0] = x0; + (*coords)[0][1] = y0; + (*coords)[0][2] = 0.0; + + // Point 2 + (*coords)[1][0] = x1; + (*coords)[1][1] = y1; + (*coords)[1][2] = 0.0; + + // Ones + (*coords)[2][0] = 1.0; + (*coords)[2][1] = 1.0; + (*coords)[2][2] = 1.0; + + this->color = color & 0x00FFFFFF; +} + +Line::Line(const Line &from){ + this->color = from.color; + this->coords = new Matrix(3,3); + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + (*coords)[i][j] = (*from.coords)[i][j]; + } + } +} + +Line::~Line(){ + delete coords; +} + +Line &Line::operator=(const Line &rhs){ + if (&rhs != this) + { + this->color = rhs.color; + delete coords; + coords = new Matrix(3,3); + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + (*coords)[i][j] = (*rhs.coords)[i][j]; + } + } + } + return *this; +} + +void Line::draw(GraphicsContext *gc, const ViewContext* vc){ + gc->setColor(color); + gc->drawLine((*coords)[0][0], (*coords)[0][1], + (*coords)[1][0], (*coords)[1][1]); +} + +void Line::out(std::ostream& os) const{ + os << "Line" << endl; + os << "Color: " << hex << setw(6) << setfill('0') << color << endl; + os << "P1: " << (*coords)[0][0] << " " << (*coords)[0][1]; + os << " " << (*coords)[0][2] << endl; + os << "P2: " << (*coords)[1][0] << " " << (*coords)[1][1]; + os << " " << (*coords)[1][2] << endl; + +} + + +Shape* Line::clone(){ + return new Line(*this); +} \ No newline at end of file diff --git a/Lab6/line.h b/Lab6/line.h new file mode 100644 index 0000000..352e58e --- /dev/null +++ b/Lab6/line.h @@ -0,0 +1,43 @@ +#ifndef line_h +#define line_h +/** + * @file line.h + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-12 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "shape.h" + +class ViewContext; + +class Line: public Shape{ + public: + // Line constructor + Line(int x0, int y0, int x1, int y1, uint32_t color); + + // Line copy constructor + Line(const Line& from); + + // Line destructor + ~Line(); + + // Line assignment operator + Line& operator=(const Line& rhs); + + // Draw function + void draw(GraphicsContext *gc, const ViewContext* vc); + + // Outputs line data to os + void out(std::ostream& os) const; + + // Clones a line + Shape* clone(); + +}; + +#endif \ No newline at end of file diff --git a/Lab6/main.cpp b/Lab6/main.cpp new file mode 100644 index 0000000..fead8eb --- /dev/null +++ b/Lab6/main.cpp @@ -0,0 +1,30 @@ +/** + * @file main.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-26 + * + * @copyright Copyright (c) 2022 + * + */ + +#include +#include +#include +#include +#include "x11context.h" +#include "mydrawing.h" +using namespace std; + +int main(void){ + + GraphicsContext* gc = new X11Context(800,600,GraphicsContext::BLACK); + gc->setColor(GraphicsContext::GREEN); + + MyDrawing md; + + gc->runLoop(&md); + + return 0; +} \ No newline at end of file diff --git a/Lab6/makefile b/Lab6/makefile new file mode 100644 index 0000000..dcfe5be --- /dev/null +++ b/Lab6/makefile @@ -0,0 +1,25 @@ +# lab6 Makefile + +CC = g++ +CFLAGS = -c -MMD -g +LFLAGS = -lX11 +# Change w/ every new project +SOURCES = main.cpp gcontext.cpp x11context.cpp row.cpp matrix.cpp shape.cpp line.cpp triangle.cpp image.cpp mydrawing.cpp viewcontext.cpp +OBJECTS = $(SOURCES:.cpp=.o) +# Change w/ every new project +EXECUTABLE = Lab6 + +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/Lab6/matrix.cpp b/Lab6/matrix.cpp new file mode 100644 index 0000000..3a67460 --- /dev/null +++ b/Lab6/matrix.cpp @@ -0,0 +1,205 @@ +/** + * @file matrix.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief Contains the main functionality for matrices of double values + * @version 1.0 + * @date 2022-03-29 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include +#include "matrix.h" + +using namespace std; + +// constructor +Matrix::Matrix(unsigned int rows, unsigned int cols){ + // Ensure size is valid + if(rows < 1 || cols < 1){ + throw(out_of_range("rows and cols must be greater than 0")); + } + // Assign given row and col size to matrix + this->rows = rows; + this->cols = cols; + // Create the row pointer + this->the_matrix = new Row*[rows]; + for(int i = 0; i < rows; i++){ + // Assign the rows of the matrix to new memory + this->the_matrix[i] = new Row(cols); + } + } + +// Copy constructor +Matrix::Matrix(const Matrix& from){ + // New matrix gets row amount from "from" matrix + this->rows = from.rows; + // New matrix gets col amount from "from" matrix + this->cols = from.cols; + // Create the row pointer with new row amount + this->the_matrix = new Row*[rows]; + for(int i = 0; i < rows; i++){ + // Set the pointer to each copied row + this->the_matrix[i] = new Row(from[i]); + } +} + +// Destructor +Matrix::~Matrix(){ + // Iterates through the pointer array and deletes each row's array + for(int i = 0; i < rows; i++) { + delete this->the_matrix[i]; + } + // Deletes the matrix itself + delete[] the_matrix; +} + +// Assignment operator +Matrix& Matrix::operator=(const Matrix& rhs){ + if(&rhs != this){ + if(rows > 0 && cols > 0){ + // Iterates through the pointer array and deletes each row's array + for(int i = 0; i < rows; i++) { + delete this->the_matrix[i]; + } + // Deletes the matrix itself + delete[] the_matrix; + } + this->rows = rhs.rows; + this->cols = rhs.cols; + this->the_matrix = new Row*[rows]; + for(int i = 0; i < rows; i++){ + // Set the pointer to each copied row + the_matrix[i] = new Row(rhs[i]); + } + } + return *this; +} + +// Named Constructor +Matrix Matrix::identity(unsigned int size){ + // Ensure size is valid + if(size < 1){ + throw(out_of_range("rows and cols must be greater than 0")); + } + // Create square matrix + Matrix result(size, size); + for(int i = 0; i < size; i++){ + // Fill each diagonal value with 1 + result[i][i] = 1; + } + return result; +} + +// Matrix addition +Matrix Matrix::operator+(const Matrix& rhs) const{ + if(rows != rhs.rows || cols != rhs.cols){ + throw(out_of_range("Matrices must be the same size")); + } + Matrix result(this->rows, this->cols); + for(int i = 0; i < rows; i++){ + for(int j = 0; j < cols; j++){ + result[i][j] = (*the_matrix[i])[j] + rhs[i][j]; + } + } + return result; +} + +// Matrix multiplication +Matrix Matrix::operator*(const Matrix& rhs) const{ + if(cols != rhs.rows){ + throw(out_of_range("1st matrix rows must equal 2nd matrix cols")); + } + Matrix result(this->rows, rhs.cols); + for(int i = 0; i < this->rows; i++){ + for(int j = 0; j < rhs.cols; j++){ + result[i][j] = 0.0; + for(int k = 0; k < rhs.rows; k++){ + result[i][j] += (*the_matrix[i])[k]*rhs[k][j]; + } + } + } + return result; +} + +// Scalar multiplication +Matrix Matrix::operator*(const double scale) const{ + Matrix result(this->rows, this->cols); + for(int i = 0; i < rows; i++){ + for(int j = 0; j < cols; j++){ + result[i][j] = (*the_matrix[i])[j]*scale; + } + } + return result; +} + +// Transpose of a Matrix +Matrix Matrix::operator~() const{ + Matrix result(this->cols, this->rows); + for(int i = 0; i < rows; i++){ + for(int j = 0; j < cols; j++){ + result[j][i] = (*the_matrix[i])[j]; + } + } + return result; +} + +// Clear Matrix +void Matrix::clear(){ + for(int i = 0; i < rows; i++) { + the_matrix[i]->clear(); + } +} + +// Access Operators - non-const +Row& Matrix::operator[](unsigned int row){ + // Ensure the row is in range + if(row > rows){ + throw(out_of_range("Row is out of range")); + } + return *(the_matrix[row]); +} + +// Access Operators - const +const Row& Matrix::operator[](unsigned int row) const{ + // Ensure the row is in range + if(row > rows){ + throw(out_of_range("Row is out of range")); + } + return *(the_matrix[row]); +} + +// print to output stream +void Matrix::out(std::ostream& os) const{ + os << setprecision(4); + os << "["; + for(int i = 0; i < rows; i++) { + if(i != 0){ + cout << " "; + } + os << "[ "; + for(int j = 0; j < cols; j++) { + os << (*the_matrix[i])[j]; + if(j != cols-1){ + os << ", "; + } + } + os << " ]"; + if(i != rows-1){ + os << endl; + } + } + os << "]" << endl; +} + +// global insertion operator +std::ostream& operator<<(std::ostream& os, const Matrix& rhs){ + rhs.out(os); + return os; +} + +// global scalar multiplication +Matrix operator*(const double scale, const Matrix& rhs){ + return rhs*scale; +} \ No newline at end of file diff --git a/Lab6/matrix.h b/Lab6/matrix.h new file mode 100644 index 0000000..0dff20e --- /dev/null +++ b/Lab6/matrix.h @@ -0,0 +1,103 @@ +#ifndef matrix_h +#define matrix_h + +#include +#include "row.h" +class Matrix +{ + public: + // No default (no argument) constructor. It doesn't really make + // sense to have one as we cannot rely on a size. This may trip + // us up later, but it will lead to a better implementation. + // matrix(); + + // Constructor - create Matrix and clear cells. If rows or + // cols is < 1, throw an exception + Matrix(unsigned int rows, unsigned int cols); + + // Copy constructor - make a new Matrix just like rhs + Matrix(const Matrix& from); + + // Destructor. Free allocated memory + ~Matrix(); + + // Assignment operator - make this just like rhs. Must function + // correctly even if rhs is a different size than this. + Matrix& operator=(const Matrix& rhs); + + // Named Constructor - produce a square identity matrix of the + // requested size. Since we do not know how the object produced will + // be used, we pretty much have to return by value. A size of 0 + // would not make sense and should throw an exception. + static Matrix identity(unsigned int size); + + // Matrix addition - lhs and rhs must be same size otherwise + // an exception shall be thrown + Matrix operator+(const Matrix& rhs) const; + + // Matrix multiplication - lhs and rhs must be compatible + // otherwise an exception shall be thrown + Matrix operator*(const Matrix& rhs) const; + + // Scalar multiplication. Note, this function will support + // someMatrixObject * 5.0, but not 5.0 * someMatrixObject. + Matrix operator*(const double scale) const; + + // Transpose of a Matrix - should always work, hence no exception + Matrix operator~() const; + + // Clear Matrix to all members 0.0 + void clear(); + + // Access Operators - throw an exception if index out of range + Row& operator[](unsigned int row); + + // const version of above - throws an exception if indices are out of + // range + const Row& operator[](unsigned int row) const; + + // I/O - for convenience - this is intended to be called by the global + // << operator declared below. + void out(std::ostream& os) const; + + private: + // An array of Row pointers size "rows" that each point to a double array + // of size "cols" + Row** the_matrix; + unsigned int rows; + unsigned int cols; + + /** routines **/ + + // add any "helper" routine here, such as routines to support + // matrix inversion + +}; + +/** Some Related Global Functions **/ + +// Overloaded global << with std::ostream as lhs, Matrix as rhs. This method +// should generate output compatible with an ostream which is commonly used +// with console (cout) and files. Something like: +// [[ r0c0, r0c1, r0c2 ] +// [ r1c0, r1c1, r1c2 ] +// [ r0c0, r0c1, r0c2 ]] +// would be appropriate. +// +// Since this is a global function, it does not have access to the private +// data of a Matrix object. So, it will need to use the public interface of +// Matrix to do its job. The method Matrix::out was added to Matrix +// specifically for this purpose. The other option would have been to make +// it a "friend" +std::ostream& operator<<(std::ostream& os, const Matrix& rhs); + +// We would normally have a corresponding >> operator, but +// will defer that exercise that until a later assignment. + + +// Scalar multiplication with a global function. Note, this function will +// support 5.0 * someMatrixObject, but not someMatrixObject * 5.0 +Matrix operator*(const double scale, const Matrix& rhs); + +#endif +// Based on lab by Dr. Darrin Rothe ((c) 2015 Dr. Darrin Rothe) diff --git a/Lab6/mydrawing.cpp b/Lab6/mydrawing.cpp new file mode 100644 index 0000000..141116a --- /dev/null +++ b/Lab6/mydrawing.cpp @@ -0,0 +1,126 @@ +#include "mydrawing.h" +//#include + +using namespace std; +MyDrawing::MyDrawing() +{ + cout << "COLORS: 'b' = blue, 'r' = red, 'g' = green \n"; + cout << "MODES: 'l' = lines, 'm' = mirror, 'd' = dotted, 'c' = connected\n"; + cout << "OTHER: 'Delete' = clear image\n"; +} +void MyDrawing::keyDown(GraphicsContext *gc, unsigned int keycode) +{ + switch (keycode) + { + case 114: // 'r', change color to red + color = GraphicsContext::RED; + break; + case 103: // 'g', change color to green + color = GraphicsContext::GREEN; + break; + case 98: // 'b', change color to blues + color = GraphicsContext::BLUE; + break; + case 65535: // 'delete', clear window + gc->clear(); + break; + case 108: // 'l', set mode to "lines" + mode = "lines"; + break; + case 109: // 'm', set mode to "mirror" + mode = "mirror"; + break; + case 99: // 'c', set mode to connected + connected = true; + break; + case 100: // 'd', set mode to dotted + connected = false; + break; + } +} +void MyDrawing::mouseButtonDown(GraphicsContext *gc, unsigned int button, int x, + int y) +{ + hold = true; // user is holding down mouse +} +void MyDrawing::mouseMove(GraphicsContext *gc, int x, int y) +{ + int dx = gc->getWindowWidth(); + int dy = gc->getWindowHeight(); + if (hold) + { // only draw when user is holding down mouse + if (mode == "lines") + { + gc->setColor(color); + //. draw line from center of window to mouse location + gc->drawLine(dx / 2, dy / 2, x, y); + } + else if (mode == "mirror") + { + gc->setColor(color); + if (firstdraw) + { + xprev = x; + yprev = y; + firstdraw = false; + } + // mirror 8 times around center in dotted or connected mode + if (!connected) + { + setLargePixel(gc, x, y); + setLargePixel(gc, y + dx / 2 - dy / 2, -x + dx / 2 + dy / 2); + setLargePixel(gc, -y + dx / 2 + dy / 2, x - dx / 2 + dy / 2); + setLargePixel(gc, -x + dx, -y + dy); + setLargePixel(gc, y + dx / 2 - dy / 2, x - dx / 2 + dy / 2); + setLargePixel(gc, -y + dx / 2 + dy / 2, -x + dx / 2 + dy / 2); + setLargePixel(gc, x, -y + dy); + setLargePixel(gc, -x + dx, y); + } + else + { + drawLargeLine(gc, xprev, yprev, x, y); + drawLargeLine(gc, yprev + dx / 2 - dy / 2, -xprev + dx / 2 + dy / 2, + y + dx / 2 - dy / 2, -x + dx / 2 + dy / 2); + drawLargeLine(gc, -yprev + dx / 2 + dy / 2, xprev - dx / 2 + dy / 2, + -y + dx / 2 + dy / 2, x - dx / 2 + dy / 2); + drawLargeLine(gc, -xprev + dx, -yprev + dy, -x + dx, -y + dy); + drawLargeLine(gc, yprev + dx / 2 - dy / 2, xprev - dx / 2 + dy / 2, + y + dx / 2 - dy / 2, x - dx / 2 + dy / 2); + drawLargeLine(gc, -yprev + dx / 2 + dy / 2, -xprev + dx / 2 + dy / 2, + -y + dx / 2 + dy / 2, -x + dx / 2 + dy / 2); + drawLargeLine(gc, xprev, -yprev + dy, x, -y + dy); + drawLargeLine(gc, -xprev + dx, yprev, -x + dx, y); + } + // draw line from previous mouse coordinate + xprev = x; + yprev = y; + } + } +} +void MyDrawing::mouseButtonUp(GraphicsContext *gc, + unsigned int button, int x, int y) +{ + // user has released mouse button + hold = false; + firstdraw = true; +} + +void drawLargeLine(GraphicsContext *gc, int x0, int y0, int x1, int y1) +{ + // draw 3 pixel wide line + gc->drawLine(x0, y0, x1, y1); + gc->drawLine(x0 + 1, y0, x1 + 1, y1); + gc->drawLine(x0 - 1, y0, x1 - 1, y1); +} +void setLargePixel(GraphicsContext *gc, int x, int y) +{ + // draw 9x9 square around pixel + gc->setPixel(x, y); + gc->setPixel(x + 1, y); + gc->setPixel(x + 1, y + 1); + gc->setPixel(x, y + 1); + gc->setPixel(x - 1, y + 1); + gc->setPixel(x - 1, y); + gc->setPixel(x - 1, y - 1); + gc->setPixel(x, y - 1); + gc->setPixel(x + 1, y - 1); \ No newline at end of file diff --git a/Lab6/mydrawing.h b/Lab6/mydrawing.h new file mode 100644 index 0000000..4559d50 --- /dev/null +++ b/Lab6/mydrawing.h @@ -0,0 +1,45 @@ +#ifndef mydrawing_h +#define mydrawing_h + +#include +#include "drawbase.h" +#include "gcontext.h" +#include "image.h" +#include "matrix.h" +using namespace std; + +class MyDrawing: public DrawingBase{ + + public: + MyDrawing(); + void keyDown(GraphicsContext* gc, unsigned int keycode); + void mouseMove(GraphicsContext* gc, int x, int y); + void mouseButtonDown(GraphicsContext* gc, + unsigned int button, int x, int y); + void mouseButtonUp(GraphicsContext* gc, + unsigned int button, int x, int y); + + private: + // default is red + unsigned int color = GraphicsContext::RED; + // indicates whether user is holding down the mouse + bool hold = false; + // "lines" mode - lines from center + // "mirror" mode - mirror 8 times around center + string mode = "lines"; + + // start of line drawn in mirror mode + int xprev; + int yprev; + // first pixel drawn in mirror mode + bool firstdraw = true; + // dotted or connected mode + bool connected = true; + Image image; + +}; + +void setLargePixel(GraphicsContext* gc, int x, int y); +void drawLargeLine(GraphicsContext* gc, int x0, int y0, int x1, int y1); + +#endif \ No newline at end of file diff --git a/Lab6/row.cpp b/Lab6/row.cpp new file mode 100644 index 0000000..18e6642 --- /dev/null +++ b/Lab6/row.cpp @@ -0,0 +1,87 @@ +/** + * @file row.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief Contains the main functionality for row matrices utilizing arrays of + * double values + * @version 1.0 + * @date 2022-03-22 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include "row.h" +using namespace std; + +// parameterized constructor +Row::Row(unsigned int length){ + // Set matrix length private variable to passed in length + this->length = length; + // Create new array in heap for row_data + this->row_data = new double[length]; + // Clear all values in new array to 0 + clear(); +} + +// copy constructor +Row::Row(const Row& from){ + // New row matrix gets length from previous matrix + this->length = from.length; + // Create new array in heap with new length + this->row_data = new double[this->length]; + // Copy all row_data values over to new array + for(int i = 0; i < this->length; i++) { + this->row_data[i] = from[i]; + } +} + +// destructor +Row::~Row(){ + // Check for valid length then free the heap memory + if(length > 0 ) { + delete[] row_data; + } +} + +// access operator (const) +double Row::operator[](unsigned int column) const{ + if (column >= length) { + throw(out_of_range("Column is out of range")); + } + return row_data[column]; +} + +// access operator (non-const) +double& Row::operator[](unsigned int column){ + if (column >= length) { + throw(out_of_range("Column is out of range")); + } + return row_data[column]; +} + +// assignment operator +Row& Row::operator= (const Row& rhs){ + if(&rhs != this){ + // Delete the current row matrix + if(length > 0){ + delete[] this->row_data; + } + // New row matrix gets length from previous matrix + this->length = rhs.length; + // Create new array in heap with new length + this->row_data = new double[this->length]; + // Copy all row_data values over to new array + for(int i = 0; i < this->length; i ++) { + this->row_data[i] = rhs.row_data[i]; + } + } + // Return address of the Row + return *this; +} + +// clear row data +void Row::clear(){ + for(int i = 0; i < length; i++) { + this->row_data[i] = 0; + } +} \ No newline at end of file diff --git a/Lab6/row.h b/Lab6/row.h new file mode 100644 index 0000000..c825715 --- /dev/null +++ b/Lab6/row.h @@ -0,0 +1,51 @@ +#ifndef row_h +#define row_h +class Row{ + public: + /* Parameterized constructor + * Takes in length and creates a row matrix with values cleared + * to zero + */ + Row(unsigned int length); + + /* Copy constructor + * Create a new row matrix with the same size and values as the + * from matrix + */ + Row(const Row& from); + + /* Destructor + * Correctly delete any heap memory + */ + ~Row(); + + /* Access operator (const version) + * Allow access to row matrix data + * Should return an exception if column is too large + */ + double operator[](unsigned int column) const; + + /* Access operator (non const version) + * Allow access to row matrix data + * Should return an exception if column is too large + */ + double& operator[] (unsigned int column); + + /* Assignment operator + * 1. Check if two sides are the same object + * 2. Delete the current row matrix + * 3. Create a new row matrix with the same size and values as + * the rhs matrix + */ + Row& operator= (const Row& rhs); + + /* Clear all data values to zero + */ + void clear(); + private: + // Row matrix data + double * row_data; + // Size of row matrix + unsigned int length; +}; +#endif diff --git a/Lab6/shape.cpp b/Lab6/shape.cpp new file mode 100644 index 0000000..42e6b7a --- /dev/null +++ b/Lab6/shape.cpp @@ -0,0 +1,22 @@ +/** + * @file shape.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-12 + * + * @copyright Copyright (c) 2022 + * + */ +#include "shape.h" + +Shape::Shape(){ + this->color = (uint32_t) 0x00FFFFFF; +} +Shape::Shape(const Shape& from){}; + +Shape::~Shape(){}; + +Shape& Shape::operator=(const Shape& rhs){ + return *this; +} diff --git a/Lab6/shape.h b/Lab6/shape.h new file mode 100644 index 0000000..3090a65 --- /dev/null +++ b/Lab6/shape.h @@ -0,0 +1,52 @@ +#ifndef shape_h +#define shape_h +/** + * @file shape.h + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-12 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include "x11context.h" +#include "matrix.h" +#include "mydrawing.h" +//#include "viewcontext.h" + +using namespace std; + +class Shape{ + public: + // Constructor + Shape(); + + // Copy Constructor + Shape(const Shape& from); + + // Destructor + virtual ~Shape(); + + // Draw shape + virtual void draw(GraphicsContext *gc, const ViewContext* vc) = 0; + + // Print to output stream + virtual void out(std::ostream& os)const = 0; + + // Virtual Constructor + virtual Shape* clone() = 0; // Pure virtual "=0" + protected: + // Matrix containing the coords of each point in the shape + Matrix* coords; + + // RGB color + uint32_t color; + + // Assignment Operator + virtual Shape& operator=(const Shape& rhs); + +}; + +#endif \ No newline at end of file diff --git a/Lab6/triangle.cpp b/Lab6/triangle.cpp new file mode 100644 index 0000000..784accd --- /dev/null +++ b/Lab6/triangle.cpp @@ -0,0 +1,95 @@ +/** + * @file triangle.cpp + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-12 + * + * @copyright Copyright (c) 2022 + * + */ +//#include "shape.h" +#include +#include "triangle.h" + +Triangle::Triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color){ + coords = new Matrix(4,3); + + // Point 1 + (*coords)[0][0] = x0; + (*coords)[0][1] = y0; + (*coords)[0][2] = 0.0; + + // Point 2 + (*coords)[1][0] = x1; + (*coords)[1][1] = y1; + (*coords)[1][2] = 0.0; + + // Point 3 + (*coords)[2][0] = x2; + (*coords)[2][1] = y2; + (*coords)[2][2] = 0.0; + + // Ones + (*coords)[3][0] = 1.0; + (*coords)[3][1] = 1.0; + (*coords)[3][2] = 1.0; + + this->color = color & 0x00FFFFFF; +} + +Triangle::Triangle(const Triangle &from){ + this->coords = new Matrix(4,3); + (*this).color = from.color; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 2; j++) + { + (*coords)[i][j] = (*from.coords)[i][j]; + } + } +} + +Triangle::~Triangle(){ + delete coords; +} + +Triangle& Triangle::operator=(const Triangle& rhs){ + if(&rhs != this){ + this->color = rhs.color; + delete coords; + coords = new Matrix(4,3); + for(int i = 0; i < 3; i++){ + for(int j = 0; j < 2; j++){ + this->coords[i][j] = rhs.coords[i][j]; + } + } + } + return *this; +} + +void Triangle::out(std::ostream& os) const{ + os << "Triangle" << endl; + os << "Color: " << hex << setw(6) << setfill('0') << color << endl; + os << "P1: " << (*coords)[0][0] << " " << (*coords)[0][1]; + os << " " << (*coords)[0][2] << endl; + os << "P2: " << (*coords)[1][0] << " " << (*coords)[1][1]; + os << " " << (*coords)[1][2] << endl; + os << "P3: " << (*coords)[2][0] << " " << (*coords)[2][1]; + os << " " << (*coords)[2][2] << endl; +} + + +Shape* Triangle::clone(){ + return new Triangle(*this); +} + +void Triangle::draw(GraphicsContext *gc, const ViewContext* vc){ + gc->setColor(color); + gc->drawLine((*coords)[0][0], (*coords)[0][1], + (*coords)[1][0], (*coords)[1][1]); + gc->drawLine((*coords)[1][0], (*coords)[1][1], + (*coords)[2][0], (*coords)[2][1]); + gc->drawLine((*coords)[2][0], (*coords)[2][1], + (*coords)[0][0], (*coords)[0][1]); +} \ No newline at end of file diff --git a/Lab6/triangle.h b/Lab6/triangle.h new file mode 100644 index 0000000..42ce88c --- /dev/null +++ b/Lab6/triangle.h @@ -0,0 +1,43 @@ +#ifndef triangle_h +#define triangle_h +/** + * @file triangle.h + * @author Trevor Barnes (barnestr@msoe.edu) + * @brief + * @version 1.0 + * @date 2022-04-12 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "shape.h" + +class ViewContext; + +class Triangle: public Shape{ + public: + // Triangle constructor + Triangle(int x0, int y0, int x1, int y1, int x2, int y2, + uint32_t color); + + // Triangle copy constructor + Triangle(const Triangle& from); + + // Triangle destructor + ~Triangle(); + + // Triangle assignment operator + Triangle& operator=(const Triangle& rhs); + + // Draw function + void draw(GraphicsContext *gc, const ViewContext* vc); + + // Outputs line data to os + void out(std::ostream& os) const; + + // Clones a triangle + Shape* clone(); + +}; +#endif \ No newline at end of file diff --git a/Lab6/viewcontext.cpp b/Lab6/viewcontext.cpp new file mode 100644 index 0000000..7f192dd --- /dev/null +++ b/Lab6/viewcontext.cpp @@ -0,0 +1,11 @@ +// - ViewContext Class - + +#include "viewcontext.h" + +ViewContext::ViewContext(){ + compMatrix = new Matrix(3,3); +} + +void ViewContext::model_to_device(){ + +} \ No newline at end of file diff --git a/Lab6/viewcontext.h b/Lab6/viewcontext.h new file mode 100644 index 0000000..c43c7e2 --- /dev/null +++ b/Lab6/viewcontext.h @@ -0,0 +1,19 @@ +#ifndef viewcontext_h +#define viewcontext_h + +#include "matrix.h" + + +class ViewContext{ + ViewContext(); + void model_to_device(); + + // Rotation - Around center of screen + // Scaling - Around center of screen + // Translation + // Reset + // Invert Colors + Matrix* compMatrix; +}; + +#endif \ No newline at end of file diff --git a/Lab6/x11context.cpp b/Lab6/x11context.cpp new file mode 100644 index 0000000..cb50144 --- /dev/null +++ b/Lab6/x11context.cpp @@ -0,0 +1,286 @@ +/* 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 +#include + +using namespace std; +/** + * 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){ + bool steep; + if(abs(y2-y1) < abs(x2-x1)){ + // Steep slope + steep = true; + if(x1 > x2){ + // Swap to change drawing direction + int temp = x1; + x1 = x2; + x2 = temp; + temp = y1; + y1 = y2; + y2 = temp; + } + } else { + // Shallow slope + steep = false; + if(y1 > y2){ + // Swap to change drawing direction + int temp = x1; + x1 = x2; + x2 = temp; + temp = y1; + y1 = y2; + y2 = temp; + } + } + // Initilize algorithm values + int dx = x2-x1; + int dy = y2-y1; + int D = 2*dy-dx; + // Will either be +1 or -1 + int c = 1; + + if(steep){ + // When |dx| > |dy| + if(dy<0){ + c = -1; + dy = -dy; + } + int D = 2*dy-dx; + int y = y1; + for(int i = x1; i < x2; i++){ + setPixel(i,y); + if(D > 0){ + y += c; + D += (2*(dy-dx)); + }else{ + D += 2*dy; + } + } + } else if(!steep){ + // When |dx| < |dy| + if(dx<0){ + c = -1; + dx = -dx; + } + int D = 2*dx-dy; + int x = x1; + for(int j = y1; j < y2; j++){ + setPixel(x,j); + if(D > 0){ + x += c; + D += (2*(dx-dy)); + } else { + D += 2*dx; + } + } + } +} + +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/Lab6/x11context.h b/Lab6/x11context.h new file mode 100644 index 0000000..cec63f4 --- /dev/null +++ b/Lab6/x11context.h @@ -0,0 +1,48 @@ +#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 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