#include #include #include #include "glwidget.h" #include "qDebug" #include "math.h" #define S 0 #define T 1 #define U 2 #define wid 512.0f #define hei 512.0f #define tailSpeed 1.5f #define bodySpeed 1.5f #define headSpeed 0.1f GLWidget::GLWidget( int timerInterval, QWidget *parent ) { if( timerInterval == 0 ) m_timer = 0; else { // sets up a QTimer object to repaint the scene at the given rate (in milliseconds) m_timer = new QTimer( this ); connect( m_timer, SIGNAL(timeout()), this, SLOT(timeOutSlot()) ); m_timer->start( timerInterval ); } rtri = rquad = rUD = rUD2 = 0.0f; udFlag = udFlag2= 1; norm_width1 = norm_height1 = norm_length1 = 0.0f; norm_width2 = norm_height2 = norm_length2 = 0.0f; normalX = normalY = normalZ = 0.0f; zm = 1; numPolygons = numCoords = directFlag = 0; isWireframe = false; controlFrame = rotateCam = controlPoint = 0; cameraPosition = 1; } // opengl initialization void GLWidget::initializeGL() { glShadeModel(GL_SMOOTH); glClearColor(0.0f, 0.0f, 0.2f, 0.0f); glClearDepth(1.0f); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // lighting stuff GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0}; GLfloat diffuse[] = {0.9, 0.9, 0.9, 1.0}; GLfloat specular[] = {0.4, 0.4, 0.4, 1.0}; GLfloat position0[] = {1.0, 1.0, 1.0, 0.0}; glLightfv( GL_LIGHT0, GL_POSITION, position0 ); glLightfv( GL_LIGHT0, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT0, GL_SPECULAR, specular ); GLfloat position1[] = {-1.0, -1.0, -1.0, 0.0}; glLightfv( GL_LIGHT1, GL_POSITION, position1 ); glLightfv( GL_LIGHT1, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT1, GL_SPECULAR, specular ); glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); glEnable( GL_LIGHT1 ); glEnable( GL_COLOR_MATERIAL ); load(); // Height of terrain if (map.load("map.ppm")) qDebug("MappPPM Image loaded successfully"); // Convert our QImage to an OpenGL friendly format map = QGLWidget::convertToGLFormat( map ); // Generate a new unique texture id and put it in texture[0] glGenTextures( 2, &texture[1] ); // Activate the texture //don't turnt that on glBindTexture( GL_TEXTURE_2D, texture[1] ); // Texture filtering : Note special filter which uses MipMaps glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // build our texture mipmaps gluBuild2DMipmaps( GL_TEXTURE_2D, 3, map.width(), map.height(), GL_RGBA, GL_UNSIGNED_BYTE, map.bits() ); glEnable(GL_TEXTURE_2D); // Enable Texture Mapping //Generating Y-coordinate's intensity (heightfield) //heightField[512][512]; for(h2 = 0; h2 < 512; h2+= 1){ //height for(w2 = 0; w2 < 512; w2+= 1){ //width heightField[h2][w2] = qGray(map.pixel(w2,h2)); } } // SKIN of terrain if (i.load("ocean_floor.jpg")) qDebug("SkinPPM Image loaded successfully"); i = QGLWidget::convertToGLFormat( i ); glGenTextures( 1, &texture[0] ); glBindTexture( GL_TEXTURE_2D, texture[0] ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); gluBuild2DMipmaps( GL_TEXTURE_2D, 3, i.width(), i.height(), GL_RGBA, GL_UNSIGNED_BYTE, i.bits() ); glEnable(GL_TEXTURE_2D); /* // skin of the shark if (skin.load("sharkSkin.jpg")) qDebug("SkinJPG Image loaded successfully"); // Convert our QImage to an OpenGL friendly format skin = QGLWidget::convertToGLFormat( skin ); // Generate a new unique texture id and put it in texture[0] glGenTextures( 4, &texture[2] ); // Activate the texture //don't turnt that on glBindTexture( GL_TEXTURE_2D, texture[1] ); // Texture filtering : Note special filter which uses MipMaps glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // build our texture mipmaps gluBuild2DMipmaps( GL_TEXTURE_2D, 3, skin.width(), skin.height(), GL_RGBA, GL_UNSIGNED_BYTE, skin.bits() ); glEnable(GL_TEXTURE_2D); // Enable Texture Mapping */ //FORM A DISPLAY LIST World = glGenLists(1); //if(!World) { // qDebug("FAIL @ WORLD GLWIDGET::initializeGL()"); //exit(1); glNewList(World, GL_COMPILE); glPushMatrix(); glTranslatef(-2400.0f, -300.0f, 0.0f); //setting the image's material properties glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glColor3f(0.3f,0.3f,0.4f); glScalef(10.0f, 1.8f, 10.0f); glBegin(GL_TRIANGLES); //setting the image's material properties float mcolor[] = { 0.5f, 0.5f, 0.5f, 0.5f }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mcolor); glTranslatef(-256.0f, 0.0f, -256.0f ); drawTerrain(); glTranslatef(-500.0f, 0.0f, -5.0f ); drawTerrain(); glTranslatef(-500.0f, 0.0f, 5.0f ); drawTerrain(); glEnd(); glPopMatrix(); glEndList(); //this will determine the first set of comtrol obtainControlPoint(); //only use this once to initialize the 64 points stored in pointCoord[65][3] getLocalSpace(); //obtaining p_zip and STU[S], STU[T] and STU[U]. getSharkSTU(); //storing the STU of the shark shark_stu[2560][3] and redefine the theCoords[2560][3] getFrameSTU(); //getting the local STU for the control points gridCP[65][3] //bernstein(); } // called whenever the window is resized, makes sure the viewport and projection matrices are updated accordingly void GLWidget::resizeGL( int width, int height ) { height = height?height:1; glViewport( 0, 0, (GLint)width, (GLint)height ); // update projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100000.0f); // modeview matrix is simply identity glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void GLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //set camera position using gluLookAt glLoadIdentity(); switch (cameraPosition) { case 1: gluLookAt(-300.0f, -5.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 50.0f, 0.0f ); break; case 2: gluLookAt(10.0f, 1500.0f, 10.0f, 0.0f, 30.0f, 0.0f, 0.0f, 50.0f, 0.0f ); glTranslatef(-150.0f, 0.0f, 100.0f); break; } //drawing sphere for control points representation if(rotateCam == 1){ glRotatef( rtri*1.5,0,1.0,0 ); } glPushMatrix(); glColor3f(0.7f,0.7f,0.7f); glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture glTranslatef(rquad*3, 0.0f,0.0f); glCallList(World); glBindTexture(GL_TEXTURE_2D, 0); // turn off Our Texture glPopMatrix(); drawObjects(); getLocalSpace(); //redefine Pzip/STU{S}{T}{U} arrays getFrameSTU(); sharkFFD(); if(controlFrame == 1){ drawFrame(); } getSharkSTU(); bernstein(); } void GLWidget::bernstein(){ //recalculate theCoord... int n = 3; float s,t,u; float valX, valY, valZ; int count; for(int c = 1; c <= 2560; c++){ s = shark_stu[c][S]; t = shark_stu[c][T]; u = shark_stu[c][U]; for(int m = 0; m <=3; m++){ blenderData[S][m] = calBlender(m,s); blenderData[T][m] = calBlender(m,t); blenderData[U][m] = calBlender(m,u); } valX = 0.0f; valY = 0.0f; valZ = 0.0f; count = 1; for(int i = 0; i <= n; i++){ for(int j = 0; j <= n; j++){ for(int k = 0; k <= n; k++){ //Pxyz * Bj(s) * Bi(t) * Bk(u) //valX += pointCoord[frameIndex[i][j][k]][X] * blenderData[S][j] * blenderData[T][i] * blenderData[U][k]; valX += pointCoord[count][X] * blenderData[S][j] * blenderData[T][i] * blenderData[U][k]; valY += pointCoord[count][Y] * blenderData[S][j] * blenderData[T][i] * blenderData[U][k]; valZ += pointCoord[count][Z] * blenderData[S][j] * blenderData[T][i] * blenderData[U][k]; count++; } } } //valX -= 153; //valY -= 153; //valZ -= 153; theCoords[c][X] += (valX - theCoords[c][X]); theCoords[c][Y] += (valY - theCoords[c][Y]); theCoords[c][Z] += (valZ - theCoords[c][Z]); //qDebug()<< c << ": " << valX << " "<< valY << " "< numCoords ) ) { qDebug("Illegal index \n"); exit( -1 ); } if ( x > maxPt[X] ) maxPt[X] = x; if ( x < minPt[X] ) minPt[X] = x; if ( y > maxPt[Y] ) maxPt[Y] = y; if ( y < minPt[Y] ) minPt[Y] = y; if ( z > maxPt[Z] ) maxPt[Z] = z; if ( z < minPt[Z] ) minPt[Z] = z; theCoords[j][X] = x; theCoords[j][Y] = y; theCoords[j][Z] = z; } fclose( f ); //qDebug(" coordinates\n"); centerPt[X] =( maxPt[X] + minPt[X] ) / 2; centerPt[Y] =( maxPt[Y] + minPt[Y] ) / 2; centerPt[Z] =( maxPt[Z] + minPt[Z] ) / 2; } /*********************************************************************/ /* Read in the list of polygons defined in the file specified by */ /* filename. The result is put in polyPoints. */ /*********************************************************************/ void GLWidget::readPolygons( char *filename ) { int i, pt, res, index; char c; FILE *f; f = fopen( filename, "r" ); if ( !f ) { qDebug("Could not open file in POLY"); exit( -1 ); } if ( fscanf( f, "%d", &( numPolygons ) ) != 1 ) { qDebug("Could not read first line of POLY "); exit( -1 ); } // CHECK WHETHER ALREADY ALLOCATED pointsPerPoly = new int[numPolygons]; polyPoints = allocate2DArrayI( numPolygons, MAX_PTS); // create an array that stores string of body part name bodyPart = new int[numPolygons]; // initialize the number of vertex per poly to zero for( i = 0 ; i < numPolygons ; i++ ){ pointsPerPoly[i] = 0; bodyPart[i] = 0; } //initialize each of the interger value to -1 for( i = 0 ; i < numPolygons ; i++ ) for( pt = 0; pt < MAX_PTS; pt++ ) polyPoints[i][pt] = -1; for( i = 0 ; i < numPolygons; i++ ) { //---- read polygon's text name ------ do{ c = fgetc( f ); if(c == 'f') bodyPart[i] = 1; if(c == 'e' || c == 'm') bodyPart[i] = 2; } while( !feof( f ) && ( c != ' ' ) ); index = 0; //---- read polygon's point numbers ---- do { // for each point in a poly res = fscanf( f, "%d", &pt ); if ( res ) { polyPoints[i][index] = pt; index++; } if ( index >= MAX_PTS ) { qDebug("Too many indices\n"); qDebug("polygon "); exit( -1 ); } } while( !feof( f ) && res ); // for each point in a poly pointsPerPoly[i] = index; } //for each element fclose( f ); //qDebug(" polygons\n"); } /* end function read_elems */ float** GLWidget::allocate2DArrayF(int nRows, int nCols) { int i; float ** ppi; float * curPtr; // (step 1) allocate memory for array of // elements pointers of column ppi = new float*[nRows]; if ( ppi == NULL ) { qDebug("allocate2DArrayF: out of memory\n"); return ppi; } // allocate block of memory curPtr = new float[nRows*nCols]; if ( curPtr == NULL ) { qDebug("allocate2DArrayF: out of memory\n"); delete [] ppi; return ppi; } // now set the pointers to the right place for( i = 0; i < nRows; i++ ) { *(ppi + i) = curPtr; curPtr += nCols; } return ppi; } /** * Dynamically allocate a 2D array of integers */ int** GLWidget::allocate2DArrayI(int nRows, int nCols) { int i; int ** ppi; int * curPtr; // (step 1) allocate memory for array of // elements pointers of column ppi = new int*[nRows]; if ( ppi == NULL ) { qDebug("allocate2DArrayI: out of memory\n"); return ppi; } // (step 2) allocate block of memory curPtr = new int[nRows*nCols]; if ( curPtr == NULL ) { qDebug("allocate2DArrayI: out of memory\n"); delete [] ppi; return ppi; } // now set the pointers to the right place for( i = 0; i < nRows; i++ ) { *(ppi + i) = curPtr; curPtr += nCols; } return ppi; } void GLWidget::free2DArrayF( float ** theArray ) { delete [] * theArray; delete [] theArray; } void GLWidget::free2DArrayI( int ** theArray ) { delete [] * theArray; delete [] theArray; } // capture keyboard events, close when Esc is pressed void GLWidget::keyPressEvent(QKeyEvent* event) { switch(event->key()) { case Qt::Key_Escape: close(); break; case Qt::Key_W: // if W is pressed toggle wireframe mode on/off isWireframe = !isWireframe; if (isWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; case Qt::Key_1: // default camera position cameraPosition = 1; break; case Qt::Key_2: // secondary camera position cameraPosition = 2; break; case Qt::Key_C: // on/off control points if(controlPoint == 1) controlPoint = 0; else controlPoint = 1; break; case Qt::Key_F: // on/off control frame if(controlFrame == 1) controlFrame = 0; else controlFrame = 1; break; case Qt::Key_R: // on/off camera rotation if(rotateCam == 1) rotateCam = 0; else rotateCam = 1; break; case Qt::Key_D: // on/off direct manipulation flag if(directFlag == 1) directFlag = 0; else directFlag = 1; break; default: event->ignore(); break; } } void GLWidget::drawTerrain(){ GLuint h, w; for(h = 0.0f; h < hei; h+= 1.0f){ //height for(w = 0.0f; w < wid; w+= 1.0f){ //width //CALCULATE NORMALS //norm_width1 = w - w; norm_width1 = 0.0f; norm_height1 = heightField[w][h+1] - heightField[w][h]; norm_length1 = (h+1.0f) - h; norm_width2 = (w+1.0f) - w; norm_height2 = heightField[w+1][h] - heightField[w][h]; //norm_length2 = h - h; norm_length2 = 0.0f; //normalX = (norm_height1 * norm_length2)- (norm_length1 * norm_height2); normalX = -(norm_length1 * norm_height2); //normalY = (norm_length1 * norm_width2) - (norm_width1 * norm_length2); normalY = (norm_length1 * norm_width2); //normalZ = (norm_width1 * norm_height2) - (norm_height1 * norm_width2); normalY = (norm_length1 * norm_width2); glNormal3f(normalX, normalY, normalZ); //RENDER AND TEXTURIZE IMAGE glTexCoord2f(w/wid, h/hei); glVertex3f(w,heightField[w][h],h); glTexCoord2f(w/wid, (h+1.0f)/hei); glVertex3f(w,heightField[w][h+1],h+1.0f); glTexCoord2f((w+1.0f)/wid, h/hei); glVertex3f(w+1.0f,heightField[w+1][h],h); } } for(h = hei; h > 0.0f; h-= 1.0f){ //height for(w = wid; w > 0.0f; w-= 1.0f){ //width //CALCULATE NORMALS norm_width1 = 0.0f; norm_height1 = heightField[w][h-1] - heightField[w][h]; norm_length1 = (h-1.0f) - h; norm_width2 = (w-1.0f) - w; norm_height2 = heightField[w-1][h] - heightField[w][h]; norm_length2 = 0.0f; normalX = -(norm_length1 * norm_height2); normalY = (norm_length1 * norm_width2); normalY = (norm_length1 * norm_width2); glNormal3f(normalX, normalY, normalZ); //RENDER IMAGE glTexCoord2f(w/wid, h/hei); glVertex3f(w,heightField[w][h],h); glTexCoord2f(w/wid, (h-1.0f)/hei); glVertex3f(w,heightField[w][h-1],h-1.0f); glTexCoord2f((w-1.0f)/wid, h/hei); glVertex3f(w-1.0f,heightField[w-1][h],h); } } } void GLWidget::sharkFFD(){ for(int i = 1; i <= 4; i++){ if(udFlag == 1){ pointCoord[i][Z] -= tailSpeed; pointCoord[i+16][Z] -= tailSpeed; pointCoord[i+32][Z] -= tailSpeed; pointCoord[i+48][Z] -= tailSpeed; }else{ pointCoord[i][Z] += tailSpeed; pointCoord[i+16][Z] += tailSpeed; pointCoord[i+32][Z] += tailSpeed; pointCoord[i+48][Z] += tailSpeed; } } for(int i = 5; i <= 8; i++){ if(udFlag == 1){ pointCoord[i][Z] += bodySpeed; pointCoord[i+16][Z] += bodySpeed; pointCoord[i+32][Z] += bodySpeed; pointCoord[i+48][Z] += bodySpeed; }else{ pointCoord[i][Z] -= bodySpeed; pointCoord[i+16][Z] -= bodySpeed; pointCoord[i+32][Z] -= bodySpeed; pointCoord[i+48][Z] -= bodySpeed; } } for(int i = 9; i <= 12; i++){ if(udFlag2 == 1){ pointCoord[i][Z] += headSpeed; pointCoord[i+16][Z] += headSpeed; pointCoord[i+32][Z] += headSpeed; pointCoord[i+48][Z] += headSpeed; }else{ pointCoord[i][Z] -= headSpeed; pointCoord[i+16][Z] -= headSpeed; pointCoord[i+32][Z] -= headSpeed; pointCoord[i+48][Z] -= headSpeed; } } for(int i = 13; i <= 16; i++){ if(udFlag2 == 1){ pointCoord[i][Z] -= headSpeed; pointCoord[i+16][Z] -= headSpeed; pointCoord[i+32][Z] -= headSpeed; pointCoord[i+48][Z] -= headSpeed; }else{ pointCoord[i][Z] += headSpeed; pointCoord[i+16][Z] += headSpeed; pointCoord[i+32][Z] += headSpeed; pointCoord[i+48][Z] += headSpeed; } } //head fin if(udFlag == 1){ pointCoord[54][Z] -= 1.0f; pointCoord[55][Z] -= 1.0f; }else{ pointCoord[54][Z] += 1.0f; pointCoord[55][Z] += 1.0f; } if(directFlag == 1){ if(udFlag == 1){ pointCoord[6][Y] -= 5.0f; pointCoord[7][Y] -= 5.0f; pointCoord[54][Y] += 5.0f; pointCoord[55][Y] += 5.0f; }else{ pointCoord[6][Y] += 5.0f; pointCoord[7][Y] += 5.0f; pointCoord[54][Y] -= 5.0f; pointCoord[55][Y] -= 5.0f; } } } // update the rotation variables and refresh the scene void GLWidget::timeOutSlot() { rtri += 0.2f; rquad += 0.7f; //swinging motion up/down for feet //swinging motion up/down for feet if(rUD >=30.0f) udFlag = 0; if(rUD <= -30.0f) udFlag = 1 ; if(udFlag == 1) rUD += 1.0f; else{ rUD -= 1.0f; } //swinging motion up/down for feet if(rUD2 >=30.0f) udFlag2 = 0; if(rUD2 <= -30.0f) udFlag2 = 1 ; if(udFlag2 == 1) rUD2 += 1.0f; else{ rUD2 -= 1.0f; } // causes the paintGL to be called updateGL(); }