//---------------------------------------------------------------------------- // EgalTech 2013-2014 //---------------------------------------------------------------------------- // File : SceneBasic.cpp Data : 03.02.14 Versione : 1.5b1 // Contenuto : Implementazione della classe gestione scena. // // // // Modifiche : 29.01.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "Scene.h" #include "/EgtDev/Include/EgtILogger.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EGkFrame3d.h" #include "/EgtDev/Include/EGkGdbConst.h" using namespace std ; //--------------------------- Constants -------------------------------------- static const double MIN_EXTENSION = 50 ; static const double MIN_ZCLIP_EXT = 5000 ; //---------------------------------------------------------------------------- IEGrScene* CreateEGrScene( void) { return static_cast ( new(nothrow) Scene) ; } //---------------------------------------------------------------------------- Scene::Scene( void) { m_pGeomDB = nullptr ; m_pLogger = nullptr ; // Context data m_hDC = nullptr ; m_hRC = nullptr ; memset( &m_wglewc, 0, sizeof( WGLEWContext)) ; memset( &m_glewc, 0, sizeof( GLEWContext)) ; m_bNewWay = false ; // Geom data SetExtension( BBox3d( -MIN_EXTENSION, -MIN_EXTENSION, -MIN_EXTENSION, MIN_EXTENSION, MIN_EXTENSION, MIN_EXTENSION)) ; // Viewport m_nViewportW = 0 ; m_nViewportH = 0 ; // View data m_ptCenter = ORIG ; SetCamera( 0, 0, 0) ; } //---------------------------------------------------------------------------- Scene::~Scene( void) { } //---------------------------------------------------------------------------- bool Scene::Init( IGeomDB* pGeomDB, ILogger* pLogger) { m_pGeomDB = pGeomDB ; m_pLogger = pLogger ; return true ; } //---------------------------------------------------------------------------- bool Scene::CreateContext( HDC hDC, int nDriver, bool b2Buff, int nColorBits, int nDepthBits) { // verifico validità Device Context if ( hDC == nullptr) return false ; m_hDC = hDC ; // riporto nei limiti il tipo di driver if ( nDriver < OD_SOFT) nDriver = OD_SOFT ; else if ( nDriver > OD_NEW) nDriver = OD_NEW ; // assegno formato pixel PIXELFORMATDESCRIPTOR pfd ; memset( &pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)) ; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR) ; pfd.nVersion = 1 ; pfd.dwFlags = ( b2Buff ? PFD_DOUBLEBUFFER : 0) | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW ; pfd.iPixelType = PFD_TYPE_RGBA ; pfd.cColorBits = nColorBits ; pfd.cDepthBits = nDepthBits ; pfd.iLayerType = PFD_MAIN_PLANE ; int nPixelFormat = ChoosePixelFormat( m_hDC, &pfd) ; if ( nPixelFormat == 0) return false ; if ( nDriver == OD_SOFT) { int nPixFormGen = ChooseGenPixelFormat( nPixelFormat, b2Buff, nColorBits, nDepthBits) ; if ( nPixFormGen != 0) nPixelFormat = nPixFormGen ; } if ( ! SetPixelFormat( m_hDC, nPixelFormat, &pfd)) return false ; HGLRC tempContext = wglCreateContext( m_hDC) ; wglMakeCurrent( m_hDC, tempContext) ; GLenum WglewInitResult ; WglewInitResult = wglewInit() ; if ( WglewInitResult != GLEW_OK) LOG_INFO( m_pLogger, "WGLEW is not initialized !") int attribs[10] ; if ( nDriver == OD_SOFT) { attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB ; attribs[1] = 1 ; attribs[2] = WGL_CONTEXT_MINOR_VERSION_ARB ; attribs[3] = 1 ; attribs[4] = 0 ; } else if ( nDriver == OD_OLD) { attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB ; attribs[1] = 2 ; attribs[2] = WGL_CONTEXT_MINOR_VERSION_ARB ; attribs[3] = 0 ; attribs[4] = 0 ; } else { attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB ; attribs[1] = 3 ; attribs[2] = WGL_CONTEXT_MINOR_VERSION_ARB ; attribs[3] = 0 ; attribs[4] = 0 ; } if ( wglewIsSupported( "WGL_ARB_create_context") == 1) { m_hRC = wglCreateContextAttribsARB( m_hDC, 0, attribs) ; wglMakeCurrent( m_hDC, NULL) ; wglDeleteContext( tempContext) ; wglMakeCurrent( m_hDC, m_hRC) ; } else { //It's not possible to make a GL 3.x context. Use the old style context (GL 2.1 and before) m_hRC = tempContext ; LOG_INFO( m_pLogger, "WGL_ARB_create_context missing !") } // verifico validità Rendering Context if ( m_hRC == nullptr) return false ; GLenum GlewInitResult ; glewExperimental = GL_TRUE ; GlewInitResult = glewInit() ; if ( GlewInitResult != GLEW_OK) LOG_INFO( m_pLogger, "GLEW is not initialized !") // verifico se posso lavorare in modalità nuova m_bNewWay = ( nDriver == OD_NEW && glewIsSupported( "GL_VERSION_3_0") == 1) ; if ( ! m_bNewWay) LOG_INFO( m_pLogger, "OpenGL old way rendering !") // reset stato di errore di OpenGL glGetError() ; return true ; } //---------------------------------------------------------------------------- int Scene::ChooseGenPixelFormat( int nPfd, bool b2Buff, int nColorBits, int nDepthBits) { PIXELFORMATDESCRIPTOR pfdR ; // verifica del pixel format proposto int nTotPfd = DescribePixelFormat( m_hDC, nPfd, sizeof(PIXELFORMATDESCRIPTOR), &pfdR) ; if ( pfdR.dwFlags & PFD_GENERIC_FORMAT && ! ( pfdR.dwFlags & PFD_GENERIC_ACCELERATED)) return nPfd ; // eventuale ricerca di un pixel format soddisfacente int nIOpt = 0 ; int nErrOpt = 1000 ; for ( int nI = 1 ; nI <= nTotPfd ; nI ++) { DescribePixelFormat( m_hDC, nI, sizeof(PIXELFORMATDESCRIPTOR), &pfdR) ; if ( pfdR.dwFlags & PFD_GENERIC_FORMAT && ! (pfdR.dwFlags & PFD_GENERIC_ACCELERATED) && ( ! b2Buff || pfdR.dwFlags & PFD_DOUBLEBUFFER)) { int nErr = abs( nColorBits - pfdR.cColorBits) + abs( nDepthBits - pfdR.cDepthBits) ; if ( nErr < nErrOpt) { nErrOpt = nErr ; nIOpt = nI ; } } } return nIOpt ; } //---------------------------------------------------------------------------- bool Scene::MakeCurrent( void) { // se RC della scena non è definito, errore if ( m_hRC == nullptr) return false ; // se RC della scena non è quello corrente, lo imposto HGLRC hRC = wglGetCurrentContext() ; if ( m_hRC != hRC) return ( wglMakeCurrent( m_hDC, m_hRC) != 0) ; return true ; } //---------------------------------------------------------------------------- string Scene::GetOpenGLInfo( void) { string sInfo = "OpenGL " ; if ( MakeCurrent()) { const char* p ; if ( ( p = reinterpret_cast ( glGetString( GL_VERSION))) != nullptr) sInfo += p ; sInfo += " " ; if ( ( p = reinterpret_cast ( glGetString( GL_VENDOR))) != nullptr) sInfo += p ; sInfo += " " ; if ( ( p = reinterpret_cast ( glGetString( GL_RENDERER))) != nullptr) sInfo += p ; } else sInfo += "ERROR" ; // reset stato di errore di OpenGL glGetError() ; return sInfo ; } //---------------------------------------------------------------------------- string Scene::GetGLSLInfo( void) { string sInfo = "GLSL " ; if ( MakeCurrent()) { const char* p ; if ( ( p = reinterpret_cast ( glGetString( GL_SHADING_LANGUAGE_VERSION))) != nullptr) sInfo += p ; else sInfo += "NONE" ; } else sInfo += "ERROR" ; // reset stato di errore di OpenGL glGetError() ; return sInfo ; } //---------------------------------------------------------------------------- string Scene::GetPixelFormatInfo( void) { string sInfo = "PixFmt " ; if ( MakeCurrent()) { int nPixFmt ; PIXELFORMATDESCRIPTOR Pfd ; if ( ( nPixFmt = GetPixelFormat( m_hDC)) > 0 && DescribePixelFormat( m_hDC, nPixFmt, sizeof(PIXELFORMATDESCRIPTOR), &Pfd) > 0) { // indice sInfo += ToString( nPixFmt) ; // tipo di driver if ( ! ( Pfd.dwFlags & PFD_GENERIC_FORMAT)) sInfo += " ICD" ; else if ( Pfd.dwFlags & PFD_GENERIC_ACCELERATED) sInfo += " MCD" ; else sInfo += " GEN" ; // singolo o doppio buffer sInfo += ( ( Pfd.dwFlags & PFD_DOUBLEBUFFER) ? " BUFF2" : " BUFF1") ; // RGBA o COLORINDEX sInfo += ( ( Pfd.iPixelType == PFD_TYPE_RGBA) ? " RGBA" : " CI") ; // color bits sInfo += ToString( Pfd.cColorBits) ; // depth bits sInfo += " Z" + ToString( Pfd.cDepthBits) ; } else sInfo = "NO DESCRIBE" ; } else sInfo += "ERROR" ; // reset stato di errore di OpenGL glGetError() ; return sInfo ; } //---------------------------------------------------------------------------- bool Scene::SetExtension( const BBox3d& b3Ext) { if ( b3Ext.IsEmpty()) return false ; m_b3ExtWorld = b3Ext ; m_bExtViewOk = false ; return true ; } //---------------------------------------------------------------------------- bool Scene::CalcExtView( void) { // verifico se il calcolo è necessario if ( m_bExtViewOk && m_bUpOk) return true ; // calcolo direzione camera Up if ( ! CalcDirUp()) return false ; // calcolo il riferimento di vista Frame3d frView ; Vector3d vtZ = m_vtDirCamera ; Vector3d vtY = m_vtUp ; Vector3d vtX = vtY ^ vtZ ; if ( ! frView.Set( m_ptCenter + m_dDistCamera * vtZ, vtX, vtY, vtZ)) return false ; // calcolo l'estensione nel riferimento di vista m_b3ExtView = m_b3ExtWorld ; m_b3ExtView.ToLoc( frView) ; m_bExtViewOk = true ; return m_bExtViewOk ; } //---------------------------------------------------------------------------- bool Scene::CalcDimViewFromExtView( void) { // calcolo estensione nel riferimento di vista if ( ! CalcExtView()) return false ; // recupero gli ingombri Point3d ptMin ; Point3d ptMax ; if ( ! m_b3ExtView.GetMinMax( ptMin, ptMax)) return false ; // ricavo le dimensioni const double COEFF = 1.05 ; double dHalfWidth = COEFF * max( fabs( ptMin.x), fabs( ptMax.x)) ; double dHalfHeight = COEFF * max( fabs( ptMin.y), fabs( ptMax.y)) ; // adatto le dimensioni a quelle della vista return AdjustDimView( dHalfWidth, dHalfHeight) ; } //---------------------------------------------------------------------------- bool Scene::AdjustDimView( double dHalfWidth, double dHalfHeight) { // se non assegnate, recupero dimensioni vista if ( m_nViewportW == 0) { HWND hWnd = ::WindowFromDC( m_hDC) ; RECT rect ; if ( ! ::GetClientRect( hWnd, &rect)) return false ; m_nViewportW = rect.right ; m_nViewportH = rect.bottom ; // aggiorno la vista glViewport( 0, 0, m_nViewportW, m_nViewportH) ; // verifico presenza errori GLenum nErr = glGetError() ; if ( nErr != GL_NO_ERROR) { string sOut = "First glViewport OpenGL error " + ToString( (int)nErr) ; LOG_INFO( m_pLogger, sOut.c_str()) } } // adatto il rapporto tra le dimensioni calcolate a quello delle dimensioni della vista double dAspect = m_nViewportH / ( double) m_nViewportW ; if ( dAspect * dHalfWidth > dHalfHeight) { m_dHalfWidth = dHalfWidth ; m_dHalfHeight = dAspect * dHalfWidth ; } else { m_dHalfWidth = dHalfHeight / dAspect ; m_dHalfHeight = dHalfHeight ; } return true ; } //---------------------------------------------------------------------------- bool Scene::CalcClippingPlanesFromExtView( void) { // calcolo estensione nel riferimento di vista if ( ! CalcExtView()) return false ; // recupero gli ingombri Point3d ptCenter ; Vector3d vtExtent ; if ( ! m_b3ExtView.GetCenterExtent( ptCenter, vtExtent)) return false ; // ricavo la posizione dei piani di clipping sull'asse Z di vista const double EXP_COEFF = 1.1 ; double dExtent = __max( ( EXP_COEFF * vtExtent.z), MIN_ZCLIP_EXT) ; m_dZNear = - ( ptCenter.z + dExtent) ; m_dZFar = - ( ptCenter.z - dExtent) ; return true ; } //---------------------------------------------------------------------------- bool Scene::Reshape( int nW, int nH) { if ( ! MakeCurrent()) return false ; // assegno le dimensioni della vista m_nViewportW = nW ; m_nViewportH = nH ; // aggiorno la vista glViewport( 0, 0, m_nViewportW, m_nViewportH) ; // verifico presenza errori GLenum nErr = glGetError() ; if ( nErr != GL_NO_ERROR) { string sOut = "Reshape OpenGL error " + ToString( (int)nErr) ; LOG_INFO( m_pLogger, sOut.c_str()) } // aggiorno AdjustDimView( m_dHalfWidth, m_dHalfHeight) ; // ridisegno return Draw() ; } //---------------------------------------------------------------------------- bool Scene::Prepare( void) { // imposto il rendering corrente if ( ! MakeCurrent()) return false ; // imposto il colore dello sfondo glClearColor( 0.1f, 0.1f, 0.5f, 0.0f) ; // eventuale ricalcolo parametri di vista CalcDirUp() ; // imposto matrice di proiezione glMatrixMode( GL_PROJECTION) ; glLoadIdentity() ; glOrtho( - m_dHalfWidth, m_dHalfWidth, - m_dHalfHeight, m_dHalfHeight, m_dZNear, m_dZFar) ; // imposto matrice modello/vista glMatrixMode( GL_MODELVIEW) ; glLoadIdentity() ; Point3d ptCamera = m_ptCenter + m_dDistCamera * m_vtDirCamera ; gluLookAt( ptCamera.x, ptCamera.y, ptCamera.z, m_ptCenter.x, m_ptCenter.y, m_ptCenter.z, m_vtUp.x, m_vtUp.y, m_vtUp.z) ; // verifico presenza errori GLenum nErr = glGetError() ; if ( nErr != GL_NO_ERROR) { string sOut = "Prepare OpenGL error " + ToString( (int)nErr) ; LOG_INFO( m_pLogger, sOut.c_str()) } return true ; } //---------------------------------------------------------------------------- bool Scene::Draw( void) { // imposto if ( ! Prepare()) return false ; // cancello glClear( GL_COLOR_BUFFER_BIT) ; // disegno DrawGroup( GDB_ID_ROOT) ; // aggiorno glFlush() ; // verifico presenza errori GLenum nErr = glGetError() ; if ( nErr != GL_NO_ERROR) { string sOut = "Draw OpenGL error " + ToString( (int)nErr) ; LOG_INFO( m_pLogger, sOut.c_str()) } // scambio i buffer back e front ( eseguita solo se previsti) if ( ! SwapBuffers( m_hDC)) LOG_INFO( m_pLogger, "Draw SwapBuffers error") return true ; } /*------------------------------------------------------------------------------------------*/ bool Scene::Project( const Point3d& ptWorld, Point3d& ptView) { if ( ! MakeCurrent()) return false ; // recupero le matrici GLdouble ModelView[ 16] ; glGetDoublev( GL_MODELVIEW_MATRIX, ModelView) ; GLdouble Projection[ 16] ; glGetDoublev( GL_PROJECTION_MATRIX, Projection) ; GLint Viewport[ 4] ; glGetIntegerv( GL_VIEWPORT, Viewport) ; // eseguo la proiezione // l'asse y della vista OpenGL va in alto con l'origine in basso, // quello di Windows va in basso con l'origine in alto int nRes =gluProject( ptWorld.x, ptWorld.y, ptWorld.z, ModelView, Projection, Viewport, &ptView.x, &ptView.y, &ptView.z) ; ptView.y = (double) Viewport[3] - ptView.y ; return ( nRes == GL_TRUE) ; } /*------------------------------------------------------------------------------------------*/ bool Scene::UnProject( const Point3d& ptView, Point3d& ptWorld) { if ( ! MakeCurrent()) return false ; // recupero le matrici GLdouble ModelView[ 16] ; glGetDoublev( GL_MODELVIEW_MATRIX, ModelView) ; GLdouble Projection[ 16] ; glGetDoublev( GL_PROJECTION_MATRIX, Projection) ; GLint Viewport[ 4] ; glGetIntegerv( GL_VIEWPORT, Viewport) ; // eseguo la contro proiezione // l'asse y della vista OpenGL va in alto con l'origine in basso, // quello di Windows va in basso con l'origine in alto int nRes = gluUnProject( ptView.x, ((double) Viewport[3] - ptView.y), ptView.z, ModelView, Projection, Viewport, &ptWorld.x, &ptWorld.y, &ptWorld.z) ; return ( nRes == GL_TRUE) ; } //---------------------------------------------------------------------------- void Scene::Destroy( void) { // cancellazione eventuali ObjEgrGraphics attaccati a oggetti geometrici DeleteObjGraphicsGroup( GDB_ID_ROOT) ; // cancellazione rendering context wglMakeCurrent( nullptr, nullptr) ; if ( m_hRC != nullptr) { wglDeleteContext( m_hRC) ; m_hRC = nullptr ; } }