#include #include #include #include #include #include #include #include #define maxVertices 1000 const int screenWidth = 640; const int screenHeight = 480; /* POINT CLASSES */ // a 2D point with integer coords class GLintPoint{ public: GLint x,y; }; // a 2D point with float coords class GLfloatPoint{ public: GLfloat x,y; }; /* VECTOR CLASSES */ // a two-vector class Vector2 { public: Vector2() { x = y = 0.0f; origin = 0; } Vector2(float xx, float yy) { x = xx; y = yy; } void set(float xx, float yy) { x = xx; y = yy; } void setX(float xx) { x = xx; } void setY(float yy) { y = yy; } float getX() { return x; } float getY() { return y; } Vector2 scale(float k) { Vector2 result; result.set(k * x, k * y); return result; } Vector2 perp() { Vector2 result; result.set(- y, x); return result; } // not tested yet! float perpdot(Vector2 v) { return ( x * v.getY() - y * v.getX() ); } Vector2 normalize() { Vector2 result; double vectorLength = x*x + y*y; if (vectorLength < 0.000000001) { cerr << "\nnormalize() in vector.cxx is about to divide by zero\n"; } float scaleFactor = 1.0/(float)sqrt(vectorLength); result.set(x * scaleFactor, y * scaleFactor); return result; } private: float x, y, origin; }; ///////////// // Vector3 ///////////// class Vector3 { public: Vector3() { x = y = z = 0.0f; origin = 0; } Vector3(float xx, float yy, float zz) { x = xx; y = yy; z = zz; } void set(float xx, float yy, float zz) { x = xx; y = yy; z = zz; } float getX() { return x; } float getY() { return y; } float getZ() { return z; } Vector3 scale(float k) { Vector3 result; result.set(k * x, k * y, k * z); return result; } Vector3 perp() { Vector3 result; result.set(- y, x, z); return result; } Vector3 normalize() { Vector3 result; double vectorLength = x*x + y*y + z*z; if (vectorLength < 0.000000001) { cerr << "\nnormalize() in vector.cxx is about to divide by zero\n"; } float scaleFactor = 1.0/(float)sqrt(vectorLength); result.set(x * scaleFactor, y * scaleFactor, z * scaleFactor); return result; } private: float x, y, z; int origin; }; //-------------------------------------------- // functions that do useful stuff with vectors //-------------------------------------------- Vector2 addVector2s (Vector2 a, Vector2 b) { Vector2 result; result.set(a.getX() + b. getX(), a.getY() + b. getY()); return result; } Vector3 addVector3s (Vector3 a, Vector3 b) { Vector3 result; result.set(a.getX() + b. getX(), a.getY() + b. getY(), a.getZ() + b. getZ()); return result; } float dotVector3s (Vector3 a, Vector3 b) { return ( (a.getX() * b.getX()) + (a.getY() * b.getY()) + (a.getZ() * b.getZ()) ); } float dotVector2s (Vector2 a, Vector2 b) { return ( (a.getX() * b.getX()) + (a.getY() * b.getY())); } Vector3 crossVector3s (Vector3 a, Vector3 b) { Vector3 result; result.set(a.getY()*b.getZ() - b.getY()*a.getZ(), b.getX()*a.getZ() - a.getX()*b.getZ(), a.getX()*b.getY() - b.getX()*a.getY()); return result; } /* 2D TRANSFORMATION MATRIX CLASS */ class TwoDXformMatrix { public: TwoDXformMatrix() { for (int i=0; i<3; i++) { for (int j=0; j<3; j++) { XformArray[i][j]=0.0; } } } TwoDXformMatrix(float m11, float m12, float m13, float m21, float m22, float m23) { XformArray[0][0] = m11; XformArray[0][1] = m12; XformArray[0][2] = m13; XformArray[1][0] = m21; XformArray[1][1] = m22; XformArray[1][2] = m23; XformArray[2][0] = XformArray[2][1] = 0; XformArray[2][2] = 1; } void setElement(int row, int col, float val) { XformArray[row][col] = val; } Vector3 getRow(int row) { Vector3 result; result.set ( XformArray[row][0], XformArray[row][1], XformArray[row][2] ); return result; } Vector3 getCol(int col) { Vector3 result; result.set ( XformArray[0][col], XformArray[1][col], XformArray[2][col] ); return result; } float getElement(int i, int j) { return XformArray[i][j]; } private: float XformArray[3][3]; }; // // drawBox() // // Draw a small box around a point // void drawBox(int x, int y) { glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINE_LOOP); glVertex2i(x-1, screenHeight - (y+1)); glVertex2i(x-1, screenHeight - (y-1)); glVertex2i(x+1, screenHeight - (y-1)); glVertex2i(x+1, screenHeight - (y+1)); glVertex2i(x-1, screenHeight - (y+1)); glEnd(); glFlush(); } // // drawPolygon() // // Given a set of vertices, draw lines between them. // void drawPolygon(int numVertices, GLintPoint vertices[]) { glColor3f(0.0, 0.0, 1.0); glBegin(GL_LINE_LOOP); for(int i = 0; i < numVertices; i++) glVertex2i(vertices[i].x, vertices[i].y); glEnd(); glFlush(); } // // transform2D() // // Take a vertex, apply a transform to it, and return it. // GLintPoint transform2D(GLintPoint vertex, TwoDXformMatrix Frob) { GLintPoint frobbedVertex; // // Hardcoded matrix-multiply. // We use rint() to round, rather than just casting. // frobbedVertex.x = (int)rint(Frob.getRow(0).getX()*vertex.x) + (int)rint(Frob.getRow(0).getY()*vertex.y) + (int)rint(Frob.getRow(0).getZ()); frobbedVertex.y = (int)rint(Frob.getRow(1).getX()*vertex.x) + (int)rint(Frob.getRow(1).getY()*vertex.y) + (int)rint(Frob.getRow(1).getZ()); return frobbedVertex; } // // drawTransformedPolygon() // // Given a set of vertices and a TwoDXformMatrix, draw the // transformed polygon // void drawTransformedPolygon(int numVertices, GLintPoint vertices[], TwoDXformMatrix Frob) { GLintPoint frobbedVertices[maxVertices]; for(int i = 0; i < numVertices; i++) { frobbedVertices[i] = transform2D(vertices[i], Frob); } glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINE_LOOP); for(int i = 0; i < numVertices; i++) glVertex2i(frobbedVertices[i].x, frobbedVertices[i].y); glEnd(); glFlush(); } // // myMouse() // // Mouse event handler. Capture left-button keypresses up to and until // a right-button event happens; then draw them as a polygon: both // in their original form and transformed by the matrix Frob // void myMouse(int button, int state, int x, int y) { static GLintPoint vertices[maxVertices]; static int numVertices = 0; // declare and initialize transform mtx // this one shrinks both coords of each vertex by a factor of 3 TwoDXformMatrix Frob(0.33, 0, 0, 0, 0.33, 0); if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) { printf("vertex entered: %d,%d \n", x, screenHeight - y); fflush(stdout); vertices[numVertices].x = x; vertices[numVertices].y = screenHeight - y; numVertices++; drawBox(x, y); } else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) { drawPolygon(numVertices, vertices); drawTransformedPolygon(numVertices, vertices, Frob); numVertices = 0; } } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLfloat)screenWidth, 0.0, (GLfloat)screenHeight); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(screenWidth, screenHeight); glutInitWindowPosition(0, 0); glutCreateWindow("transformations"); glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLfloat)screenWidth, 0.0, (GLfloat) screenHeight); glutDisplayFunc(display); glutMouseFunc(myMouse); glutMainLoop(); }