void display(void) { kuhl_limitfps(100); dgr_update(); // Make sure slaves get updates ASAP dgr_setget("currentTex", ¤tTexture, sizeof(int)); /* If the texture has changed since we were previously in display() */ if(alreadyDisplayedTexture != currentTexture) { // Load the new texture loadTexture(currentTexture); // Keep a record of which texture we are currently displaying // so we can detect when DGR changes currentTexture on a // slave. alreadyDisplayedTexture = currentTexture; } /* The view frustum is an orthographic frustum for this * application. The size of the frustum doesn't matter much, but * the aspect ratio of the frustum should match the aspect ratio * of the screen/window. */ float frustum[6], masterFrustum[6]; /* The following two methods will get the master view frustum and * the current process view frustum. If we are running in a * standalone version, these two frustums will be the same. */ projmat_get_master_frustum(masterFrustum); projmat_get_frustum(frustum, -1, -1); // frustum of this process (master or slave) /* Set this view frustum for this process. */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(frustum[0],frustum[1], frustum[2],frustum[3], -1, 1); glMatrixMode(GL_MODELVIEW); // Middle of master frustum in the vertical direction. It divides the top // tiles from the bottom tiles. float masterFrustumMid = (masterFrustum[2]+masterFrustum[3])/2; // Dimensions of the master view frustum float masterFrustumWidth = masterFrustum[1]-masterFrustum[0]; float masterFrustumHeight = masterFrustum[3]-masterFrustum[2]; // The width of the quad (in frustum units). Since the image will // be stretched to fit the screen vertically, and our units are in // frustum units, the width of the tile is the height of the // frustum times the aspect ratio divided by the number of tiles // in the horizontal direction. float quadWidth = aspectRatio * masterFrustumHeight; float tileWidth = quadWidth/numTiles; // TODO: Maybe just scale the image vertically if the image almost fits in the screen horizontally? int msSincePictureDisplayed = glutGet(GLUT_ELAPSED_TIME)-lastAdvance; int scrollStatus = 0; // 0=don't need to scroll or done scrolling, 1=currently scrolling if(masterFrustumWidth < quadWidth)// do we need to scroll on this image { // Do we still need to scroll? if(scrollAmount < quadWidth-masterFrustumWidth) scrollStatus = 1; if(scrollStatus == 1) { // Wait a few seconds before scrolling. It takes a while // for all slaves on IVS to get the images. if(msSincePictureDisplayed > 5000) scrollAmount = ((msSincePictureDisplayed-5000) / (SCROLL_SPEED*1000.0))*masterFrustumWidth; else scrollAmount = 0; // If we calculated the scroll amount to be the largest // scrollAmount we'll need if(scrollAmount > quadWidth-masterFrustumWidth) { // dwell at the end of the image even if autoadvance is on. int now = glutGet(GLUT_ELAPSED_TIME); // make sure we still have a few seconds before advancing if(SLIDESHOW_WAIT*1000-(now-lastAdvance) < 3000) { // Go back and set lastAdvance time so we have // some time to dwell here. lastAdvance = now-SLIDESHOW_WAIT*1000+3000; } } } } dgr_setget("scrollAmount", &scrollAmount, sizeof(float)); /* If autoadvance is set and we are not scrolling (or done * scrolling) figure out if it is now time to advance to the next * image. */ if(autoAdvance == 1 && scrollStatus != 1) { // printf("time since last advance %d\n", glutGet(GLUT_ELAPSED_TIME)-lastAdvance); if(glutGet(GLUT_ELAPSED_TIME)-lastAdvance > SLIDESHOW_WAIT*1000) // time to show new image: { currentTexture = getNextTexture(); loadTexture(currentTexture); return; } } glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glColor3f(1,1,1); // color of quad // Draw the top and bottom quad for each of the tiles going across the screen horizontally. */ for(GLuint i=0; i<numTiles*2; i=i+2) { float tileLeft = (i/2 )*tileWidth + masterFrustum[0]; float tileRight = (i/2+1)*tileWidth + masterFrustum[0]; // Draw bottom tile glBindTexture(GL_TEXTURE_2D, texNames[i]); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2d(tileLeft -scrollAmount, masterFrustum[2]); // lower left glTexCoord2f(1.0, 0.0); glVertex2d(tileRight-scrollAmount, masterFrustum[2]); // lower right glTexCoord2f(1.0, 1.0); glVertex2d(tileRight-scrollAmount, masterFrustumMid); // upper right glTexCoord2f(0.0, 1.0); glVertex2d(tileLeft -scrollAmount, masterFrustumMid); // upper left glEnd(); // Draw top tile glBindTexture(GL_TEXTURE_2D, texNames[i+1]); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2d(tileLeft -scrollAmount, masterFrustumMid); // lower left glTexCoord2f(1.0, 0.0); glVertex2d(tileRight-scrollAmount, masterFrustumMid); // lower right glTexCoord2f(1.0, 1.0); glVertex2d(tileRight-scrollAmount, masterFrustum[3]); // upper right glTexCoord2f(0.0, 1.0); glVertex2d(tileLeft -scrollAmount, masterFrustum[3]); // upper left glEnd(); } glDisable(GL_TEXTURE_2D); /* Draw filename label on top of a quad. */ glColor4f(0,0,0,.3); glBegin(GL_QUADS); glVertex2d(-1,-1); glVertex2d(-.5,-1); glVertex2d(-.5,-.96); glVertex2d(-1,-.96); glEnd(); glColor4f(1,1,1,.9); glRasterPos2f(-.98,-.98); void *font = GLUT_BITMAP_TIMES_ROMAN_24; char *str = globalargv[currentTexture]; for(GLuint i=0; i<strlen(str); i++) glutBitmapCharacter(font, str[i]); /* Flush and swap the OpenGL buffers. */ glFlush(); glutSwapBuffers(); glutPostRedisplay(); }
/* Called by GLUT whenever the window needs to be redrawn. This * function should not be called directly by the programmer. Instead, * we can call glutPostRedisplay() to request that GLUT call display() * at some point. */ void display() { /* If we are using DGR, send or receive data to keep multiple * processes/computers synchronized. */ dgr_update(); dgr_setget("style", &renderStyle, sizeof(int)); /* Render the scene once for each viewport. Frequently one * viewport will fill the entire screen. However, this loop will * run twice for HMDs (once for the left eye and once for the * right. */ viewmat_begin_frame(); for(int viewportID=0; viewportID<viewmat_num_viewports(); viewportID++) { viewmat_begin_eye(viewportID); /* Where is the viewport that we are drawing onto and what is its size? */ int viewport[4]; // x,y of lower left corner, width, height viewmat_get_viewport(viewport, viewportID); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); /* Clear the current viewport. Without glScissor(), glClear() * clears the entire screen. We could call glClear() before * this viewport loop---but on order for all variations of * this code to work (Oculus support, etc), we can only draw * after viewmat_begin_eye(). */ glScissor(viewport[0], viewport[1], viewport[2], viewport[3]); glEnable(GL_SCISSOR_TEST); glClearColor(.2,.2,.2,0); // set clear color to grey glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); glEnable(GL_DEPTH_TEST); // turn on depth testing kuhl_errorcheck(); /* Turn on blending (note, if you are using transparent textures, the transparency may not look correct unless you draw further items before closer items.). */ glEnable(GL_BLEND); glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); /* Get the view or camera matrix; update the frustum values if needed. */ float viewMat[16], perspective[16]; viewmat_get(viewMat, perspective, viewportID); glUseProgram(program); kuhl_errorcheck(); /* Send the perspective projection matrix to the vertex program. */ glUniformMatrix4fv(kuhl_get_uniform("Projection"), 1, // number of 4x4 float matrices 0, // transpose perspective); // value float modelMat[16]; get_model_matrix(modelMat); float modelview[16]; mat4f_mult_mat4f_new(modelview, viewMat, modelMat); // modelview = view * model /* Send the modelview matrix to the vertex program. */ glUniformMatrix4fv(kuhl_get_uniform("ModelView"), 1, // number of 4x4 float matrices 0, // transpose modelview); // value glUniform1i(kuhl_get_uniform("renderStyle"), renderStyle); // Copy far plane value into vertex program so we can render depth buffer. float f[6]; // left, right, bottom, top, near>0, far>0 projmat_get_frustum(f, viewport[2], viewport[3]); glUniform1f(kuhl_get_uniform("farPlane"), f[5]); kuhl_errorcheck(); kuhl_limitfps(60); update(); kuhl_geometry_draw(modelgeom); /* Draw the model */ kuhl_errorcheck(); glUseProgram(0); // stop using a GLSL program. } // finish viewport loop viewmat_end_frame(); /* Check for errors. If there are errors, consider adding more * calls to kuhl_errorcheck() in your code. */ kuhl_errorcheck(); // kuhl_video_record("videoout", 30); /* Ask GLUT to call display() again. We shouldn't call display() * ourselves recursively because it will not leave time for GLUT * to call other callback functions for when a key is pressed, the * window is resized, etc. */ glutPostRedisplay(); }