//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : ObjNewGraphics.cpp Data : 23.04.14 Versione : 1.5d5 // Contenuto : Implementazione della classe grafica di un oggetto geometrico. // // // // Modifiche : 10.02.14 DS Creazione modulo. // 23.04.14 DS Agg. gestione materiali. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "ObjNewGraphics.h" #include "Scene.h" #include "GraphObjs.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkGdbConst.h" #include "/EgtDev/Include/EGkTriangle3d.h" //--------------------------- Macro e Costanti ------------------------------- // Dimensioni flag per edge di triangoli const size_t SIZEFLAG = sizeof( unsigned char) ; // Dimensioni record del buffer ( vertice + normale + flag) const size_t SIZEVNF = ( 2 * SIZEV3F + SIZEFLAG) ; //---------------------------------------------------------------------------- ObjNewGraphics::~ObjNewGraphics( void) { Clear() ; } //---------------------------------------------------------------------------- void ObjNewGraphics::Reset( void) { m_bValid = false ; m_nCurrMode = GL_NONE ; } //---------------------------------------------------------------------------- void ObjNewGraphics::Clear( void) { DeleteVaoVbo() ; m_ngaVect.clear() ; m_bValid = false ; m_nCurrMode = GL_NONE ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddColor( const Color& colC) { return AddColor( colC.GetRed(), colC.GetGreen(), colC.GetBlue(), colC.GetAlpha()) ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddMaterial( const Color& colAmb, const Color& colDiff, const Color& colSpec, float fShin) { return AddMaterial( NgAtom::MAT_A, colAmb.GetRed(), colAmb.GetGreen(), colAmb.GetBlue(), colDiff.GetAlpha()) && AddMaterial( NgAtom::MAT_D, colDiff.GetRed(), colDiff.GetGreen(), colDiff.GetBlue(), colDiff.GetAlpha()) && AddMaterial( NgAtom::MAT_S, colSpec.GetRed(), colSpec.GetGreen(), colSpec.GetBlue(), colDiff.GetAlpha()) && AddMaterial( NgAtom::MAT_SH, fShin, 0, 0, 0) ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddBackMaterial( const Color& colAmbDiff) { return AddMaterial( NgAtom::MAT_B, colAmbDiff.GetRed(), colAmbDiff.GetGreen(), colAmbDiff.GetBlue(), colAmbDiff.GetAlpha()) ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddPoint( const Point3d& ptP, bool bAux) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // definisco i buffer per la scheda grafica e vi inserisco i nuovi vertici unsigned int nVaoId ; glGenVertexArrays( 1, &nVaoId) ; if ( nVaoId == 0) return false ; glBindVertexArray( nVaoId) ; unsigned int nVboId ; glGenBuffers( 1, &nVboId) ; if ( nVboId == 0) { glBindVertexArray( 0) ; glDeleteVertexArrays( 1, &nVaoId) ; return false ; } glBindBuffer( GL_ARRAY_BUFFER, nVboId) ; glBufferData( GL_ARRAY_BUFFER, 1 * SIZEV3F, NULL, GL_STATIC_DRAW) ; Vert3f v3V( ptP) ; glBufferSubData( GL_ARRAY_BUFFER, 0, SIZEV3F, &v3V) ; m_b3Loc.Add( ptP) ; int nCount = 1 ; glVertexPointer( 3, GL_FLOAT, 0, ((void*)(0))) ; glEnableClientState( GL_VERTEX_ARRAY) ; glBindVertexArray( 0) ; // aggiungo i dati in lista AddVerts( GL_POINTS, nCount, nVaoId, nVboId, bAux) ; // dichiaro valida la grafica m_bValid = true ; return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddPoints( const PNTVECTOR& vPnt, bool bAux) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // definisco i buffer per la scheda grafica e vi inserisco i nuovi vertici unsigned int nVaoId ; glGenVertexArrays( 1, &nVaoId) ; if ( nVaoId == 0) return false ; glBindVertexArray( nVaoId) ; unsigned int nVboId ; glGenBuffers( 1, &nVboId) ; if ( nVboId == 0) { glBindVertexArray( 0) ; glDeleteVertexArrays( 1, &nVaoId) ; return false ; } glBindBuffer( GL_ARRAY_BUFFER, nVboId) ; int nCount = int( vPnt.size()) ; glBufferData( GL_ARRAY_BUFFER, nCount * SIZEV3F, NULL, GL_STATIC_DRAW) ; Vert3f v3V ; for ( int i = 0 ; i < nCount ; ++ i) { v3V.Set( vPnt[i]) ; glBufferSubData( GL_ARRAY_BUFFER, i * SIZEV3F, SIZEV3F, &v3V) ; m_b3Loc.Add( vPnt[i]) ; } glVertexPointer( 3, GL_FLOAT, 0, ((void*)(0))) ; glEnableClientState( GL_VERTEX_ARRAY) ; glBindVertexArray( 0) ; // aggiungo i dati in lista AddVerts( GL_POINTS, nCount, nVaoId, nVboId, bAux) ; // dichiaro valida la grafica m_bValid = true ; return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddLines( const PNTVECTOR& vPnt, bool bAux) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // definisco i buffer per la scheda grafica e vi inserisco i nuovi vertici unsigned int nVaoId ; glGenVertexArrays( 1, &nVaoId) ; if ( nVaoId == 0) return false ; glBindVertexArray( nVaoId) ; unsigned int nVboId ; glGenBuffers( 1, &nVboId) ; if ( nVboId == 0) { glBindVertexArray( 0) ; glDeleteVertexArrays( 1, &nVaoId) ; return false ; } glBindBuffer( GL_ARRAY_BUFFER, nVboId) ; int nCount = int( vPnt.size()) ; glBufferData( GL_ARRAY_BUFFER, nCount * SIZEV3F, NULL, GL_STATIC_DRAW) ; Vert3f v3V ; for ( int i = 0 ; i < nCount ; ++ i) { v3V.Set( vPnt[i]) ; glBufferSubData( GL_ARRAY_BUFFER, i * SIZEV3F, SIZEV3F, &v3V) ; m_b3Loc.Add( vPnt[i]) ; } glVertexPointer( 3, GL_FLOAT, 0, ((void*)(0))) ; glEnableClientState( GL_VERTEX_ARRAY) ; glBindVertexArray( 0) ; // aggiungo i dati in lista AddVerts( GL_LINES, nCount, nVaoId, nVboId, bAux) ; // dichiaro valida la grafica m_bValid = true ; return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddPolyLine( const PolyLine& PL, bool bAux) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // definisco i buffer per la scheda grafica e vi inserisco i nuovi vertici unsigned int nVaoId ; glGenVertexArrays( 1, &nVaoId) ; if ( nVaoId == 0) return false ; glBindVertexArray( nVaoId) ; unsigned int nVboId ; glGenBuffers( 1, &nVboId) ; if ( nVboId == 0) { glBindVertexArray( 0) ; glDeleteVertexArrays( 1, &nVaoId) ; return false ; } glBindBuffer( GL_ARRAY_BUFFER, nVboId) ; glBufferData( GL_ARRAY_BUFFER, PL.GetPointNbr() * SIZEV3F, NULL, GL_STATIC_DRAW) ; Point3d ptP ; Vert3f v3V ; int nCount = 0 ; for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP)) { v3V.Set( ptP) ; glBufferSubData( GL_ARRAY_BUFFER, nCount * SIZEV3F, SIZEV3F, &v3V) ; m_b3Loc.Add( ptP) ; ++ nCount ; } glVertexPointer( 3, GL_FLOAT, 0, ((void*)(0))) ; glEnableClientState( GL_VERTEX_ARRAY) ; glBindVertexArray( 0) ; // aggiungo i dati in lista AddVerts( GL_LINE_STRIP, nCount, nVaoId, nVboId, bAux) ; // dichiaro valida la grafica m_bValid = true ; return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::StartTriangles( int nNum, bool bAux) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // modo corrente deve essere nullo if ( m_nCurrMode != GL_NONE) return false ; // inizializzo emissione triangoli unsigned int nVaoId ; glGenVertexArrays( 1, &nVaoId) ; if ( nVaoId == 0) return false ; glBindVertexArray( nVaoId) ; unsigned int nVboId ; glGenBuffers( 1, &nVboId) ; if ( nVboId == 0) { glBindVertexArray( 0) ; glDeleteVertexArrays( 1, &nVaoId) ; return false ; } glBindBuffer( GL_ARRAY_BUFFER, nVboId) ; // NumTria * 3 * dimensione( vertice+normale+flag) glBufferData( GL_ARRAY_BUFFER, nNum * 3 * SIZEVNF, NULL, GL_STATIC_DRAW) ; // aggiungo i dati in lista AddVerts( GL_TRIANGLES, 0, nVaoId, nVboId, bAux) ; // dichiaro modo triangoli m_nCurrMode = GL_TRIANGLES ; return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::AddTriangle( const Triangle3d& Tria, const TriFlags3d& TFlags, const TriNormals3d& TNrms) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // modo corrente deve essere triangoli if ( m_nCurrMode != GL_TRIANGLES) return false ; // recupero il conteggio dei vertici int nCount = m_ngaVect.back().m_nCount ; // emetto i vertici, le normali e i flag del triangolo #pragma pack( push, 1) struct VnfBuf { Vert3f v3V ; Vert3f v3N ; unsigned char cFlag ; } ; #pragma pack( pop) VnfBuf Buffer[3] ; for ( int i = 0 ; i < 3 ; ++ i) { Buffer[i].v3V = Tria.GetP( i) ; Buffer[i].v3N = TNrms.vtN[i] ; Buffer[i].cFlag = ( TFlags.bFlag[i] ? 1 : 0) ; } glBufferSubData( GL_ARRAY_BUFFER, nCount * SIZEVNF, 3 * SIZEVNF, Buffer) ; // aggiorno il conteggio nCount += 3 ; m_ngaVect.back().m_nCount = nCount ; // aggiorno bbox for ( int i = 0 ; i < 3 ; ++ i) m_b3Loc.Add( Tria.GetP( i)) ; return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::EndTriangles( void) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // modo corrente deve essere triangoli if ( m_nCurrMode != GL_TRIANGLES) return false ; // termino il modo triangoli glVertexPointer( 3, GL_FLOAT, SIZEVNF, ((void*)(0))) ; glEnableClientState( GL_VERTEX_ARRAY) ; glNormalPointer( GL_FLOAT, SIZEVNF, ((void*)( 1 * SIZEV3F))) ; glEnableClientState( GL_NORMAL_ARRAY) ; glEdgeFlagPointer( SIZEVNF, ((void*)( 2 * SIZEV3F))) ; glEnableClientState( GL_EDGE_FLAG_ARRAY) ; glBindVertexArray( 0) ; // dichiaro modalità standard m_nCurrMode = GL_NONE ; // dichiaro valida la grafica m_bValid = true ; return true ; } //---------------------------------------------------------------------------- static float* AdjustColor( float fCol[4], bool bDark) { if ( ! bDark) { return fCol ; } else { static float fDarkCol[4] = { fCol[0], fCol[1], fCol[2], fCol[3]} ; fDarkCol[0] = fCol[0] * 0.6f ; fDarkCol[1] = fCol[1] * 0.6f ; fDarkCol[2] = fCol[2] * 0.6f ; fDarkCol[3] = fCol[3] * 0.6f ; return fDarkCol ; } } //---------------------------------------------------------------------------- bool ObjNewGraphics::Draw( int nStat, int nMark, bool bSurfSha, bool bSurf, int nAlpha, bool bShowAux) { if ( ! m_bValid || m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // se vuoto non faccio alcunché if ( m_ngaVect.size() == 0) return true ; // gestione stato di visualizzazione if ( nStat == GDB_ST_OFF) return true ; if ( nStat == GDB_ST_SEL) { glPointSize( (float) m_pScene->GetSelPointSize()) ; glLineWidth( (float) m_pScene->GetSelLineWidth()) ; } // colori speciali per superficie shading selezionata o marcata bool bStdCol = true ; float fSelMarkCol[4] = { 1, 1, 1, 1} ; float fSelMarkBackCol[4] = { 0.75, 0.75, 0.75, 1} ; if ( bSurfSha) { if ( nMark == GDB_MK_ON) { bStdCol = false ; Color colMark = m_pScene->GetMark() ; colMark.SetAlpha( nAlpha) ; colMark.GetFloat( fSelMarkCol) ; Color colMarkBack = GetSurfBackColor( colMark) ; colMarkBack.SetAlpha( nAlpha) ; colMarkBack.GetFloat( fSelMarkBackCol) ; } else if ( nStat == GDB_ST_SEL) { bStdCol = false ; Color colSelSurf = m_pScene->GetSelSurf() ; colSelSurf.SetAlpha( nAlpha) ; colSelSurf.GetFloat( fSelMarkCol) ; Color colSelSurfBack = GetSurfBackColor( colSelSurf) ; colSelSurfBack.SetAlpha( nAlpha) ; colSelSurfBack.GetFloat( fSelMarkBackCol) ; } } // determino se devo scurire il colore wireframe bool bDark = false ; if ( bStdCol && bSurf && ! bSurfSha) { Color colBT, colBB ; m_pScene->GetBackground( colBT, colBB) ; int nColMid = ( colBT.GetIntIntensity() + colBB.GetIntIntensity()) / 2 ; bDark = ( nColMid > 127) ; } // ciclo di disegno for ( auto iIter = m_ngaVect.begin() ; iIter != m_ngaVect.end() ; ++ iIter) { switch ( iIter->m_nType) { case NgAtom::VERTS : if ( iIter->m_nCount > 0 && iIter->m_nVaoId != 0) { glBindVertexArray( iIter->m_nVaoId) ; glDrawArrays( iIter->m_nMode, 0, iIter->m_nCount) ; glBindVertexArray( 0) ; } break ; case NgAtom::VERTS_A : if ( bShowAux && iIter->m_nCount > 0 && iIter->m_nVaoId != 0) { glBindVertexArray( iIter->m_nVaoId) ; glDrawArrays( iIter->m_nMode, 0, iIter->m_nCount) ; glBindVertexArray( 0) ; } break ; case NgAtom::COLOR : glColor4fv( ( bStdCol ? AdjustColor( iIter->m_fCol, bDark) : fSelMarkCol)) ; break ; case NgAtom::MAT_A : glMaterialfv( GL_FRONT, GL_AMBIENT, ( bStdCol ? iIter->m_fCol : fSelMarkCol)) ; break ; case NgAtom::MAT_D : glMaterialfv( GL_FRONT, GL_DIFFUSE, ( bStdCol ? iIter->m_fCol : fSelMarkCol)) ; break ; case NgAtom::MAT_S : glMaterialfv( GL_FRONT, GL_SPECULAR, ( bStdCol ? iIter->m_fCol : fSelMarkCol)) ; break ; case NgAtom::MAT_SH : glMaterialf( GL_FRONT, GL_SHININESS, iIter->m_fCol[0]) ; break ; case NgAtom::MAT_B : glMaterialfv( GL_BACK, GL_AMBIENT_AND_DIFFUSE, ( bStdCol ? iIter->m_fCol : fSelMarkBackCol)) ; break ; } } // se marcato e non superficie in shading, disegno halo if ( nMark == GDB_MK_ON && ! bSurfSha) { // cambio test di depth per non sovrascrivere il disegno appena fatto glDepthFunc( GL_LESS) ; // dimensioni per halo glPointSize( (float) m_pScene->GetMarkPointSize()) ; glLineWidth( (float) m_pScene->GetMarkLineWidth()) ; // colore di marcatura Color colMark = m_pScene->GetMark() ; glColor4f( colMark.GetRed(), colMark.GetGreen(), colMark.GetBlue(), colMark.GetAlpha()) ; // ciclo di disegno for ( auto iIter = m_ngaVect.begin() ; iIter != m_ngaVect.end() ; ++ iIter) { switch ( iIter->m_nType) { case NgAtom::VERTS : if ( iIter->m_nCount > 0 && iIter->m_nVaoId != 0) { glBindVertexArray( iIter->m_nVaoId) ; glDrawArrays( iIter->m_nMode, 0, iIter->m_nCount) ; glBindVertexArray( 0) ; } break ; case NgAtom::VERTS_A : if ( bShowAux && iIter->m_nCount > 0 && iIter->m_nVaoId != 0) { glBindVertexArray( iIter->m_nVaoId) ; glDrawArrays( iIter->m_nMode, 0, iIter->m_nCount) ; glBindVertexArray( 0) ; } break ; // non si impostano i colori, si usa quello di marcatura } } // ripristino test di depth glDepthFunc( GL_LEQUAL) ; } // se necessario, ripristino la normale visualizzazione if ( nStat == GDB_ST_SEL || nMark == GDB_MK_ON) { glPointSize( (float) m_pScene->GetPointSize()) ; glLineWidth( (float) m_pScene->GetLineWidth()) ; } return true ; } //---------------------------------------------------------------------------- bool ObjNewGraphics::DeleteVaoVbo( void) { if ( m_pScene == nullptr || ! m_pScene->MakeCurrent()) return false ; // ciclo di cancellazione VAO/VBO for ( auto iIter = m_ngaVect.begin() ; iIter != m_ngaVect.end() ; ++ iIter) { if ( iIter->m_nType == NgAtom::VERTS && iIter->m_nCount > 0) { glBindBuffer( GL_ARRAY_BUFFER, 0) ; glDeleteBuffers( 1, &iIter->m_nVboId) ; glBindVertexArray( 0) ; glDeleteVertexArrays( 1, &iIter->m_nVaoId) ; iIter->m_nCount = 0 ; } } return true ; }