- // Second Partial Exam
- // Fernando Dingler - A01127501
- // June 15, 2011
- #include <cmath>
- #include <iostream>
- #include <stdio.h>
- #include "GlutWin.h"
- #include "Camera.h"
- #include "Vector3.h"
- #include <fstream>
- #include <assert.h>
- #include <windows.h>
- #include <math.h>
- #include <GL/gl.h>
- #include <GL/glut.h>
- #include <string.h>
- using namespace std;
- typedef unsigned short ushort;
- typedef unsigned long ulong;
- typedef unsigned char uchar;
- fstream inf; // global in this file for convenience
- // Texture variables
- static GLuint textures[1];
- bool applyTexture = false;
- GlutWin *win;
- Camera *camera;
- // mouse cursor position
- float mouse_x,
- mouse_y;
- bool mouse_updated = false;
- // describe the section of the curve, and how often to sample
- float t_0 = 0.0;
- float t_end = 0.1;
- float t_incr = 0.5;
- // describes shape of polygon extruded along curve
- // and which is a common n-gon
- int n_gon = 4;
- // Light Components
- static float globAmb = 0.3;
- static float globDif = 0.4;
- static float globSpe = 0.7;
- // Materials
- int material_index = 1;
- // Material Components
- static float globMatAmb = 0.5;
- static float globMatDif = 0.5;
- static float globMatSpe = 0.5;
- static float globExp = 4.0;
- float max_radius;
- float min_radius;
- float aux = 1.0;
- // For objects with fixed material properties
- // Four arrays, each containing the corresponding material
- // properties for:
- // row 0: Black plastic
- // row 1: Brass
- // row 2: Bronze
- // row 3: Chrome
- // row 4: Copper
- // row 5: Gold
- // row 6: Pewter
- // row 7: Silver
- // row 8: Polished Silver
- static float matAmb[9][3] = {{0.0, 0.0, 0.0},
- {0.329412, 0.223529, 0.027451},
- {0.2125, 0.1275, 0.054},
- {0.25, 0.25, 0.25},
- {0.19125, 0.0735, 0.0225},
- {0.24725, 0.1995, 0.0745},
- {0.10588, 0.058824, 0.113725},
- {0.19225, 0.19225, 0.19225},
- {0.23125, 0.23125, 0.23125} };
- static float matDif[9][3] = {{0.01, 0.01, 0.01},
- {0.780392, 0.568627, 0.113725},
- {0.714, 0.4284, 0.18144},
- {0.4, 0.4, 0.4},
- {0.7038, 0.27048, 0.0828},
- {0.75164, 0.60648, 0.22648},
- {0.427451, 0.470588, 0.541176},
- {0.50754, 0.50754, 0.50754},
- {0.2775, 0.2775, 0.2775} };
- static float matSpe[9][3] = {{0.50, 0.50, 0.50},
- {0.992157, 0.941176, 0.807843},
- {0.393548, 0.271906, 0.166721},
- {0.774597, 0.774597, 0.774597},
- {0.256777, 0.137622, 0.086014},
- {0.628281, 0.555802, 0.366065},
- {0.3333, 0.3333, 0.521569},
- {0.508273, 0.508273, 0.508273},
- {0.773911, 0.773911, 0.773911} };
- static float matExp[9] = {32.0, 27.8974, 25.6, 76.8, 12.8, 51.2, 9.84615, 51.2, 89.6};
- // Class for textures
- // A few class definitions
- class mRGB {
- public:
- unsigned char r,g,b;
- mRGB(){r = g = b = 0;}
- mRGB(mRGB& p){r = p.r; g = p.g; b = p.b;}
- mRGB(uchar rr, uchar gg, uchar bb){r = rr; g = gg; b = bb;}
- void set(uchar rr, uchar gg, uchar bb){r = rr; g = gg; b = bb;}
- };
- ushort getShort() //helper function
- { //BMP format uses little-endian integer types
- // get a 2-byte integer stored in little-endian form
- char ic;
- ushort ip;
- inf.get(ic); ip = ic; //first byte is little one
- inf.get(ic); ip |= ((ushort)ic << 8); // or in high order byte
- return ip;
- }
- //<<<<<<<<<<<<<<<<<<<< getLong >>>>>>>>>>>>>>>>>>>
- ulong getLong() //helper function
- { //BMP format uses little-endian integer types
- // get a 4-byte integer stored in little-endian form
- ulong ip = 0;
- char ic = 0;
- unsigned char uc = ic;
- inf.get(ic); uc = ic; ip = uc;
- inf.get(ic); uc = ic; ip |=((ulong)uc << 8);
- inf.get(ic); uc = ic; ip |=((ulong)uc << 16);
- inf.get(ic); uc = ic; ip |=((ulong)uc << 24);
- return ip;
- }
- class RGBpixmap {
- public:
- int nRows, nCols;
- mRGB *pixel;
- float gr, gg, gb;
- int readBMPFile(char *fname);
- void SetTexColor(float rin, float gin, float bin);
- void SetTexture(GLuint textureName);
- };
- void RGBpixmap::SetTexColor(float rin, float gin, float bin)
- {
- // Set multipliers to set the color of the parameterized textures
- gg = gin;
- gr = rin;
- gb = bin;
- }
- int RGBpixmap:: readBMPFile(char *fname)
- {
- // Read into memory an mRGB image from an uncompressed BMP file.
- // return 0 on failure, 1 on success
- inf.open(fname, ios::in|ios::binary); //read binary char's
- if(!inf){ cout << " can't open file: " << fname << endl; return 0;}
- int k, row, col, numPadBytes, nBytesInRow;
- // read the file header information
- char ch1, ch2;
- inf.get(ch1); inf.get(ch2); //type: always 'BM'
- ulong fileSize = getLong();
- ushort reserved1 = getShort(); // always 0
- ushort reserved2= getShort(); // always 0
- ulong offBits = getLong(); // offset to image - unreliable
- ulong headerSize = getLong(); // always 40
- ulong numCols = getLong(); // number of columns in image
- ulong numRows = getLong(); // number of rows in image
- ushort planes= getShort(); // always 1
- ushort bitsPerPixel= getShort(); //8 or 24; allow 24 here
- ulong compression = getLong(); // must be 0 for uncompressed
- ulong imageSize = getLong(); // total bytes in imag
- ulong xPels = getLong(); // always 0
- ulong yPels = getLong(); // always 0
- ulong numLUTentries = getLong(); // 256 for 8 bit, otherwise 0
- ulong impColors = getLong(); // always 0
- if(bitsPerPixel != 24)
- { // error - must be a 24 bit uncompressed image
- cout << "not a 24 bit/pixelimage, or is compressed!\n";
- inf.close(); return 0;
- }
- //add bytes at end of each row so total # is a multiple of 4
- // round up 3*numCols to next mult. of 4
- nBytesInRow = ((3 * numCols + 3)/4) * 4;
- numPadBytes = nBytesInRow - 3 * numCols; // need this many
- nRows = numRows; // set class's data members
- nCols = numCols;
- pixel = new mRGB[nRows * nCols]; //make space for array
- if(!pixel) return 0; // out of memory!
- long count = 0;
- char dum;
- for(row = 0; row < nRows; row++) // read pixel values
- {
- for(col = 0; col < nCols; col++)
- {
- char r,g,b;
- inf.get(b); inf.get(g); inf.get(r); //read bytes
- pixel[count].r = r; //place them in colors
- pixel[count].g = g;
- pixel[count++].b = b;
- }
- for(k = 0; k < numPadBytes ; k++) //skip pad bytes at row's end
- inf >> dum;
- }
- inf.close(); return 1; // success
- }
- void RGBpixmap::SetTexture(GLuint textureName)
- {
- // Set texture parameters to initial values
- // Set wrapping and interpolation
- glBindTexture(GL_TEXTURE_2D, textureName);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, nCols, nRows, 0, GL_RGB, GL_UNSIGNED_BYTE, pixel);
- }
- RGBpixmap myTexs[1];
- // Function that describes the curve
- // Parametric representation
- Vector3 C( float t ) {
- return( Vector3( 2.0 * sin(t), 2.0 * cos(t), 0.5 * t ) );
- }
- // Generate the matrix transformation that corresponds to the
- // Frenet frame for the current t.
- // The output is an array (mat[]) with 16 elements, in
- // column major order. See hint for output below
- void create_frenet_frame( double t, float mat[] ) {
- Vector3 N, B, T, C2, C1, C0;
- // Numerically calculate deriv and 2nd deriv
- // Approximation for this function is too unstable
- C0 = Vector3( 2.0*sin(t), 2.0*cos(t), t * 0.5); // evaluation of parametric function
- // Can also do
- // C0 = C(t);
- // CHANGE THE PARAMETRIC FUNCTION
- // FOR EXAMPLE, PG 295 HILL & KELLEY
- C1 = Vector3( 2.0*cos(t), 2.0*(-sin(t)),0.5);// TO DO - First derivative: Obtain analytically (by hand)
- C2 = Vector3( 2.0*(-sin(t)), 2.0*(-cos(t)),0.0);// TO DO - Second derivative: Obtain analytically (by hand)
- // calculate vectors that define the frenet frame
- // at this point on the curve
- T = C1;
- T.normalize();
- B = C2;
- B.normalize();
- N = B.cross( T );
- // create affine transform matrix
- // assume mat has 16 elems
- mat[ 0] = N.x; mat[ 4] = B.x; mat[ 8] = T.x; mat[12] = C0.x;
- mat[ 1] = N.y; mat[ 5] = B.y; mat[ 9] = T.y; mat[13] = C0.y;
- mat[ 2] = N.z; mat[ 6] = B.z; mat[10] = T.z; mat[14] = C0.z;
- mat[ 3] = 0.0; mat[ 7] = 0.0; mat[11] = 0.0; mat[15] = 1.00;
- }
- void updateLights( void )
- {
- // Update LIGHT properties
- GLfloat myAmb[] = {globAmb, globAmb, globAmb, 1.0};
- GLfloat myDif[] = {globDif, globDif, globDif, 1.0};
- GLfloat mySpe[] = {globSpe, globSpe, globSpe, 1.0};
- glLightfv(GL_LIGHT0, GL_AMBIENT, myAmb);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, myDif);
- glLightfv(GL_LIGHT0, GL_SPECULAR, mySpe);
- }
- bool initdemo() {
- // initialize GLUT class
- win = new GlutWin( 600, 800, 100, 100, GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH, "Extrusion Demo" );
- camera = new Camera();
- camera->set( 5, 5, 5, 0, 5, 5, 0, 1, 0 );
- glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
- glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
- // enable depth testing
- glEnable( GL_DEPTH_TEST );
- // enable textures
- glEnable(GL_TEXTURE_2D);
- // set up lighting in ogl
- glEnable( GL_LIGHTING );
- float light_amb[] = { 0.5, 0.5, 0.5, 1.0 };
- float light_dif[] = { 0.25, 0.25, 0.25, 1.0 };
- float light_pos[] = { 0.0, 0.0, 0.0, 1.0 };
- float material_amb[] = { 1.0, 1.0, 1.0, 1.0 };
- float material_dif[] = { 1.0, 1.0, 1.0, 1.0 };
- glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, material_amb );
- glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, material_dif );
- glLightfv( GL_LIGHT0, GL_AMBIENT, light_amb );
- glLightfv( GL_LIGHT0, GL_DIFFUSE, light_dif );
- glLightfv( GL_LIGHT0, GL_POSITION, light_pos );
- glEnable( GL_LIGHT0 );
- // Generate textures
- glGenTextures(1, textures);
- myTexs[0].SetTexColor(1.0, 0.2, 0.2);
- myTexs[0].readBMPFile("yugioh.bmp");
- myTexs[0].SetTexture(textures[0]);
- return( true );
- }
- Vector3 matrixmult( float mat[], Vector3 v, float t ) {
- return( Vector3( mat[ 0]*v.x*t + mat[ 4]*v.y*t + mat[ 8] *v.z*t + mat[12],
- mat[ 1]*v.x*t + mat[ 5]*v.y*t + mat[ 9] *v.z*t + mat[13],
- mat[ 2]*v.x*t + mat[ 6]*v.y*t + mat[10] *v.z*t + mat[14] ) );
- }
- void render() {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the screen
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
- // Update lights so the user can see the changes in the parameters modified by the keyboard
- updateLights();
- glMaterialfv(GL_FRONT, GL_AMBIENT, matAmb[material_index]);
- glMaterialfv(GL_FRONT, GL_DIFFUSE, matDif[material_index]);
- glMaterialfv(GL_FRONT, GL_SPECULAR, matSpe[material_index]);
- glMaterialf(GL_FRONT, GL_SHININESS, matExp[material_index]);
- float mat1[16], mat2[16];
- glPointSize( 3.0 );
- // Auxiliar variables to subdive the texture image.
- float b = 0.0;
- float d = 0.0;
- float c = 1.0/aux;
- // Define max and minimun size of the radius
- max_radius = 1.5;
- min_radius = 0.5;
- for( float t = t_0; t <= t_end; t += t_incr ) {
- c = 1.0/aux;
- // calculate frenet frames for this waist and the next one
- create_frenet_frame( t, mat1 );
- create_frenet_frame( t+t_incr, mat2 );
- glMatrixMode( GL_MODELVIEW );
- glPushMatrix();
- // calc vertices for this "waist" -
- // the points located at each Frenet frame
- // These points will be the vertices used to create the polygons
- Vector3 waist1[25], waist2[25], norm[25];
- // create polygon - approximation of a circle
- double anginc = ( 2.0 * 3.14159 / double( n_gon ) );
- double ang = 0.0;
- for( int k = 0; k < n_gon; k++ ) {
- // This function approximates a circle (r = 0.4) using a N-gon
- // Therefore, each polygon vertex is defined in this manner
- // The larger n_gon, the smoother the circle approximation
- Vector3 pos = Vector3( 0.4 * cos( ang ), 0.4 * sin( ang ), 0.0 );
- ang += anginc;
- // Add different scaling to a given waist
- waist1[k] = matrixmult( mat1, pos, min_radius );
- waist2[k] = matrixmult( mat2, pos, max_radius );
- }
- // calc normal vectors per surface
- // based on Newell Method
- for( int j = 0; j < n_gon; j++ ) {
- Vector3 t1 = ( waist1[j] - waist2[j] );
- Vector3 t2 = ( waist1[j] + waist2[j] );
- norm[j].x = t1.y * t2.z;
- norm[j].y = t1.z * t2.x;
- norm[j].z = t1.x * t2.y;
- t1 = ( waist2[j] - waist2[(j+1)%n_gon] );
- t2 = ( waist2[j] + waist2[(j+1)%n_gon] );
- norm[j].x += t1.y * t2.z;
- norm[j].y += t1.z * t2.x;
- norm[j].z += t1.x * t2.y;
- t1 = ( waist2[(j+1)%n_gon] - waist1[(j+1)%n_gon] );
- t2 = ( waist2[(j+1)%n_gon] + waist1[(j+1)%n_gon] );
- norm[j].x += t1.y * t2.z;
- norm[j].y += t1.z * t2.x;
- norm[j].z += t1.x * t2.y;
- norm[j].normalize();
- }
- // Calculate range for applying texture based on n_gon
- float af = 1.0/n_gon;
- // render face
- glBegin( GL_QUADS );
- // Create a quad for each edge of two adyacent n-gons
- // DON'T FORGET TO LINK THE FIRST WITH THE LAST ONE (index = 0 and index = n_gon - 1)
- for( int a = 0; a < n_gon; a++ ){
- // Add different color to faces
- glNormal3f( norm[a].x,norm[a].y,norm[a].z);
- // Apply texture
- glBindTexture(GL_TEXTURE_2D, textures[0]);
- // Vertices from "first" n-gon index, for both waists. Hint: a
- glTexCoord2f(0.0 + d, 0.0 + b); glVertex3f(waist1[a].x,waist1[a].y,waist1[a].z);
- glTexCoord2f(0.0 + d, af + b); glVertex3f(waist2[a].x,waist2[a].y,waist2[a].z);
- // Same vertices from "second" n-gon index, for both waists. Hint: a+1
- glTexCoord2f(c + d, af + b); glVertex3f( waist2[(a+1)%n_gon].x,waist2[(a+1)%n_gon].y,waist2[(a+1)%n_gon].z);
- glTexCoord2f(c + d, 0 + b); glVertex3f( waist1[(a+1)%n_gon].x,waist1[(a+1)%n_gon].y,waist1[(a+1)%n_gon].z);
- // increment the auxiliar variable to subdivide the image
- b += af;
- if(b >= 1.0){
- b=0.0;
- }
- }
- glEnd();
- glPopMatrix();
- // Reset the radius factors to create the effect of a crushed shape
- min_radius = (max_radius <= 0.5)? 0.5 : 1.5;
- max_radius = (max_radius <= 0.5)? 1.5 : 0.5;
- d += c;
- }
- // refresh image
- glutSwapBuffers();
- glutPostRedisplay();
- }
- void kb_input( unsigned char key, int x, int y ) {
- switch( key ) {
- // light controls
- case 'j': globAmb = min(1.0,globAmb+0.1); break;
- case 'k': globDif = min(1.0,globDif+0.1); break;
- case 'l': globSpe = min(1.0,globSpe+0.1); break;
- case 'J': globAmb = max(0.0,globAmb-0.1); break;
- case 'K': globDif = max(0.0,globDif-0.1); break;
- case 'L': globSpe = max(0.0,globSpe-0.1); break;
- // camera and navigation controls
- case 'a': camera->slide( -1.0, 0.0, 0.0 ); break;
- case 'd': camera->slide( 1.0, 0.0, 0.0 ); break;
- case 's': camera->slide( 0.0, 0.0, 1.0 ); break;
- case 'w': camera->slide( 0.0, 0.0, -1.0 ); break;
- case '[': if( t_incr >= 0.01 ) t_incr /= 2.0; break;
- case ']': if( t_incr < 0.5 ) t_incr *= 2.0; break;
- case '+': t_end += 1.0; aux += 2.0; break;
- case '-': t_end -= 1.0; aux -= 2.0; break;
- case '/': if( n_gon < 20) n_gon++; break;
- case '*': if( n_gon > 3 ) n_gon--; break;
- // material controls
- case '1': material_index = 1; glDisable(GL_TEXTURE_2D); break;
- case '2': material_index = 2; glDisable(GL_TEXTURE_2D); break;
- case '3': material_index = 3; glDisable(GL_TEXTURE_2D); break;
- case '4': material_index = 4; glDisable(GL_TEXTURE_2D); break;
- case '5': material_index = 5; glDisable(GL_TEXTURE_2D); break;
- case '6': material_index = 6; glDisable(GL_TEXTURE_2D); break;
- case '7': material_index = 7; glDisable(GL_TEXTURE_2D); break;
- case '8': material_index = 8; glDisable(GL_TEXTURE_2D); break;
- case '9': material_index = 0; glDisable(GL_TEXTURE_2D); break;
- // enable texture
- case '0': glEnable(GL_TEXTURE_2D); break;
- // exit keys
- case 'q':
- case 'Q':
- case 27:
- exit( 0 );
- default: break;
- }
- glutPostRedisplay();
- }
- void mouse_motion( int x, int y ) {
- float dx, dy;
- if( ! mouse_updated) {
- mouse_x = x;
- mouse_y = y;
- mouse_updated = true;
- }else{
- // calc delta
- dx = x - mouse_x;
- dy = y - mouse_y;
- mouse_x = x;
- mouse_y = y;
- // determine rotation amount
- camera->pitch( dy / 5.0 );
- camera->yaw( dx );
- }
- }
- int main() {
- if( initdemo() ) {
- glutDisplayFunc( render );
- glutKeyboardFunc( kb_input );
- glutPassiveMotionFunc( mouse_motion );
- glutMainLoop();
- delete win;
- delete camera;
- }
- }