//------------------------------------------------------------------------------- /// /// \file viewport.cpp /// \author Cem Yuksel (www.cemyuksel.com) /// \version 9.0 /// \date August 21, 2019 /// /// \brief Example source for CS 6620 - University of Utah. /// //------------------------------------------------------------------------------- #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include "scene.h" #include "objects.h" #include "lights.h" #include "materials.h" #include "texture.h" #include #include #ifdef USE_GLUT # ifdef __APPLE__ # include # else # include # endif #else # include #endif //------------------------------------------------------------------------------- void BeginRender(); // Called to start rendering (renderer must run in a separate thread) void StopRender(); // Called to end rendering (if it is not already finished) extern Node rootNode; extern Camera camera; extern RenderImage renderImage; extern LightList lights; extern TexturedColor background; //------------------------------------------------------------------------------- enum Mode { MODE_READY, // Ready to render MODE_RENDERING, // Rendering the image MODE_RENDER_DONE // Rendering is finished }; enum ViewMode { VIEWMODE_OPENGL, VIEWMODE_IMAGE, VIEWMODE_Z, VIEWMODE_SAMPLECOUNT, }; enum MouseMode { MOUSEMODE_NONE, MOUSEMODE_DEBUG, MOUSEMODE_ROTATE, }; static Mode mode = MODE_READY; // Rendering mode static ViewMode viewMode = VIEWMODE_OPENGL; // Display mode static MouseMode mouseMode = MOUSEMODE_NONE; // Mouse mode static int startTime; // Start time of rendering static int mouseX=0, mouseY=0; static float viewAngle1=0, viewAngle2=0; static GLuint viewTexture; static int dofDrawCount = 0; static Color *dofImage = nullptr; static Color24 *dofBuffer = nullptr; #define MAX_DOF_DRAW 32 //------------------------------------------------------------------------------- void GlutDisplay(); void GlutReshape(int w, int h); void GlutIdle(); void GlutKeyboard(unsigned char key, int x, int y); void GlutMouse(int button, int state, int x, int y); void GlutMotion(int x, int y); //------------------------------------------------------------------------------- void ShowViewport() { int argc = 1; char argstr[] = "raytrace"; char *argv = argstr; glutInit(&argc,&argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH ); if (glutGet(GLUT_SCREEN_WIDTH) > 0 && glutGet(GLUT_SCREEN_HEIGHT) > 0){ glutInitWindowPosition( (glutGet(GLUT_SCREEN_WIDTH) - camera.imgWidth)/2, (glutGet(GLUT_SCREEN_HEIGHT) - camera.imgHeight)/2 ); } else glutInitWindowPosition( 50, 50 ); glutInitWindowSize(camera.imgWidth, camera.imgHeight); glutCreateWindow("Ray Tracer - CS 6620"); glutDisplayFunc(GlutDisplay); glutReshapeFunc(GlutReshape); glutIdleFunc(GlutIdle); glutKeyboardFunc(GlutKeyboard); glutMouseFunc(GlutMouse); glutMotionFunc(GlutMotion); Color bg = background.GetColor(); glClearColor(bg.r,bg.g,bg.b,0); glPointSize(3.0); glEnable( GL_CULL_FACE ); float zero[] = {0,0,0,0}; glLightModelfv( GL_LIGHT_MODEL_AMBIENT, zero ); glEnable(GL_NORMALIZE); glLineWidth(2); if ( camera.dof > 0 ) { dofBuffer = new Color24[ camera.imgWidth * camera.imgHeight ]; dofImage = new Color[ camera.imgWidth * camera.imgHeight ]; memset( dofImage, 0, camera.imgWidth * camera.imgHeight * sizeof(Color) ); } glGenTextures(1,&viewTexture); glBindTexture(GL_TEXTURE_2D, viewTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glutMainLoop(); } //------------------------------------------------------------------------------- void GlutReshape(int w, int h) { if( w != camera.imgWidth || h != camera.imgHeight ) { glutReshapeWindow( camera.imgWidth, camera.imgHeight); } else { glViewport( 0, 0, w, h ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); float r = (float) w / float (h); gluPerspective( camera.fov, r, 0.02, 1000.0); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); } } //------------------------------------------------------------------------------- void DrawNode( Node *node ) { glPushMatrix(); const Material *mtl = node->GetMaterial(); if ( mtl ) mtl->SetViewportMaterial(); Matrix3f tm = node->GetTransform(); Vec3f p = node->GetPosition(); float m[16] = { tm[0],tm[1],tm[2],0, tm[3],tm[4],tm[5],0, tm[6],tm[7],tm[8],0, p.x,p.y,p.z,1 }; glMultMatrixf( m ); Object *obj = node->GetNodeObj(); if ( obj ) obj->ViewportDisplay(mtl); for ( int i=0; iGetNumChild(); i++ ) { DrawNode( node->GetChild(i) ); } glPopMatrix(); } //------------------------------------------------------------------------------- void DrawScene() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); const TextureMap *bgMap = background.GetTexture(); if ( bgMap ) { glDepthMask(GL_FALSE); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); Color c = background.GetColor(); glColor3f(c.r,c.g,c.b); if ( bgMap->SetViewportTexture() ) { glEnable( GL_TEXTURE_2D ); glMatrixMode( GL_TEXTURE ); Matrix3f tm = bgMap->GetInverseTransform(); Vec3f p = tm * bgMap->GetPosition(); float m[16] = { tm[0],tm[1],tm[2],0, tm[3],tm[4],tm[5],0, tm[6],tm[7],tm[8],0, -p.x,-p.y,-p.z,1 }; glLoadMatrixf( m ); glMatrixMode( GL_MODELVIEW ); } else { glDisable( GL_TEXTURE_2D ); } glBegin(GL_QUADS); glTexCoord2f(0,1); glVertex2f(-1,-1); glTexCoord2f(1,1); glVertex2f( 1,-1); glTexCoord2f(1,0); glVertex2f( 1, 1); glTexCoord2f(0,0); glVertex2f(-1, 1); glEnd(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glDepthMask(GL_TRUE); glDisable( GL_TEXTURE_2D ); } glEnable( GL_LIGHTING ); glEnable( GL_DEPTH_TEST ); glPushMatrix(); Vec3f p = camera.pos; Vec3f t = camera.pos + camera.dir*camera.focaldist; Vec3f u = camera.up; if ( camera.dof > 0 ) { Vec3f v = camera.dir ^ camera.up; float r = sqrtf(float(rand())/RAND_MAX)*camera.dof; float a = float(M_PI) * 2.0f * float(rand())/RAND_MAX; p += r*cosf(a)*v + r*sinf(a)*u; } gluLookAt( p.x, p.y, p.z, t.x, t.y, t.z, u.x, u.y, u.z ); glRotatef( viewAngle1, 1, 0, 0 ); glRotatef( viewAngle2, 0, 0, 1 ); if ( lights.size() > 0 ) { for ( unsigned int i=0; iSetViewportLight(i); } } else { float white[] = {1,1,1,1}; float black[] = {0,0,0,0}; Vec4f p(camera.pos, 1); glEnable ( GL_LIGHT0 ); glLightfv( GL_LIGHT0, GL_AMBIENT, black ); glLightfv( GL_LIGHT0, GL_DIFFUSE, white ); glLightfv( GL_LIGHT0, GL_SPECULAR, white ); glLightfv( GL_LIGHT0, GL_POSITION, &p.x ); } DrawNode(&rootNode); glPopMatrix(); glDisable( GL_DEPTH_TEST ); glDisable( GL_LIGHTING ); glDisable( GL_TEXTURE_2D ); } //------------------------------------------------------------------------------- void DrawImage( void *data, GLenum type, GLenum format ) { glBindTexture(GL_TEXTURE_2D, viewTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, renderImage.GetWidth(), renderImage.GetHeight(), 0, format, type, data); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); glEnable(GL_TEXTURE_2D); glMatrixMode( GL_TEXTURE ); glLoadIdentity(); glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); glColor3f(1,1,1); glBegin(GL_QUADS); glTexCoord2f(0,1); glVertex2f(-1,-1); glTexCoord2f(1,1); glVertex2f(1,-1); glTexCoord2f(1,0); glVertex2f(1,1); glTexCoord2f(0,0); glVertex2f(-1,1); glEnd(); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glDisable(GL_TEXTURE_2D); } //------------------------------------------------------------------------------- void DrawProgressBar(float done) { glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); glBegin(GL_LINES); glColor3f(1,1,1); glVertex2f(-1,-1); glVertex2f(done*2-1,-1); glColor3f(0,0,0); glVertex2f(done*2-1,-1); glVertex2f(1,-1); glEnd(); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); } //------------------------------------------------------------------------------- void DrawRenderProgressBar() { int rp = renderImage.GetNumRenderedPixels(); int np = renderImage.GetWidth() * renderImage.GetHeight(); if ( rp >= np ) return; float done = (float) rp / (float) np; DrawProgressBar(done); } //------------------------------------------------------------------------------- void GlutDisplay() { switch ( viewMode ) { case VIEWMODE_OPENGL: if ( dofImage ) { if ( dofDrawCount < MAX_DOF_DRAW ) { DrawScene(); glReadPixels( 0, 0, camera.imgWidth, camera.imgHeight, GL_RGB, GL_UNSIGNED_BYTE, dofBuffer ); for ( int i=0, y=0; y 0 ) { mtl->SetViewportMaterial(0); nextMtlSwith = GetMaterialFaceCount(0); nextMtlID = 1; } glBegin(GL_TRIANGLES); for ( unsigned int i=0; i= nextMtlSwith ) { if ( nextMtlID >= NM() ) nextMtlSwith = NF(); else { glEnd(); nextMtlSwith += GetMaterialFaceCount(nextMtlID); mtl->SetViewportMaterial(nextMtlID); nextMtlID++; glBegin(GL_TRIANGLES); } } for ( int j=0; j<3; j++ ) { if ( HasTextureVertices() ) glTexCoord3fv( &VT( FT(i).v[j] ).x ); if ( HasNormals() ) glNormal3fv( &VN( FN(i).v[j] ).x ); glVertex3fv( &V( F(i).v[j] ).x ); } } glEnd(); } void MtlBlinn::SetViewportMaterial(int subMtlID) const { ColorA c; c = ColorA(diffuse.GetColor()); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, &c.r ); c = ColorA(specular.GetColor()); glMaterialfv( GL_FRONT, GL_SPECULAR, &c.r ); glMaterialf( GL_FRONT, GL_SHININESS, glossiness*1.5f ); const TextureMap *dm = diffuse.GetTexture(); if ( dm && dm->SetViewportTexture() ) { glEnable( GL_TEXTURE_2D ); glMatrixMode( GL_TEXTURE ); Matrix3f tm = dm->GetInverseTransform(); Vec3f p = tm * dm->GetPosition(); float m[16] = { tm[0],tm[1],tm[2],0, tm[3],tm[4],tm[5],0, tm[6],tm[7],tm[8],0, -p.x,-p.y,-p.z,1 }; glLoadMatrixf( m ); glMatrixMode( GL_MODELVIEW ); } else { glDisable( GL_TEXTURE_2D ); } } void GenLight::SetViewportParam(int lightID, ColorA ambient, ColorA intensity, Vec4f pos ) const { glEnable ( GL_LIGHT0 + lightID ); glLightfv( GL_LIGHT0 + lightID, GL_AMBIENT, &ambient.r ); glLightfv( GL_LIGHT0 + lightID, GL_DIFFUSE, &intensity.r ); glLightfv( GL_LIGHT0 + lightID, GL_SPECULAR, &intensity.r ); glLightfv( GL_LIGHT0 + lightID, GL_POSITION, &pos.x ); } bool TextureFile::SetViewportTexture() const { if ( viewportTextureID == 0 ) { glGenTextures(1,&viewportTextureID); glBindTexture(GL_TEXTURE_2D,viewportTextureID); gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, &data[0].r ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); } glBindTexture(GL_TEXTURE_2D,viewportTextureID); return true; } bool TextureChecker::SetViewportTexture() const { if ( viewportTextureID == 0 ) { const int texSize = 256; glGenTextures(1,&viewportTextureID); glBindTexture(GL_TEXTURE_2D,viewportTextureID); Color24 c[2] = { Color24(color1), Color24(color2) }; Color24 *tex = new Color24[texSize*texSize]; for ( int i=0; i= 128 ) ix = 1 - ix; tex[i] = c[ix]; } gluBuild2DMipmaps( GL_TEXTURE_2D, 3, texSize, texSize, GL_RGB, GL_UNSIGNED_BYTE, &tex[0].r ); delete [] tex; glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); } glBindTexture(GL_TEXTURE_2D,viewportTextureID); return true; } //------------------------------------------------------------------------------- //-------------------------------------------------------------------------------