Files
EgtGraphics/SceneBasic.cpp
Dario Sassi ac78227f0b EgtGraphics :
- piccoli aggiustamenti su ZoomOnPoint e ZoomWin per impostazione centro vista.
2026-05-14 16:07:02 +02:00

1017 lines
32 KiB
C++

//----------------------------------------------------------------------------
// 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.
// 21.10.14 DS Aggiunta gestione Unselectable.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "Scene.h"
#include "GraphObjs.h"
#include "DllMain.h"
#include "/EgtDev/Include/EGrDllMain.h"
#include "/EgtDev/Include/EgtILogger.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EGkFrame3d.h"
#include "/EgtDev/Include/EGkGdbConst.h"
#include "/EgtDev/Include/EGkGeomDB.h"
#include "/EgtDev/Include/SELkKeyProc.h"
#include "/EgtDev/Include/EgtKeyCodes.h"
using namespace std ;
//--------------------------- Constants --------------------------------------
static const double MIN_EXTENSION = 250 ;
static const double MIN_W_H = 0.01 ;
static const double MIN_ZCLIP_EXT = 25000 ;
//----------------------------------------------------------------------------
IEGrScene*
CreateEGrScene( void)
{
// verifico la chiave e le opzioni
if ( ! VerifyKey( 0))
return nullptr ;
// creo l'oggetto
return static_cast<IEGrScene*> ( new(nothrow) Scene) ;
}
//----------------------------------------------------------------------------
Scene::Scene( void)
{
// Context data
m_hDC = nullptr ;
m_hRC = nullptr ;
m_nOglVer = 0 ;
m_bNewWay = false ;
// Camera e viewport
m_ptCenter = ORIG ;
m_nOrizzOffsCamera = 0 ;
SetCamera( 0, 0, 0) ;
m_nViewportW = 0 ;
m_nViewportH = 0 ;
m_bOrthographic = true ;
m_nPerspZoomType = ZT_STD ;
// Textures
m_TextMgr.SetScene( this) ;
// Sfondo
m_colBackTop.Set( 176, 176, 176) ;
m_colBackBottom.Set( 176, 176, 176) ;
// Modalità di visualizzazione
m_nShowMode = SM_WIREFRAME ;
m_bShowCurveDirection = false ;
m_bShowTriaAdvanced = true ;
m_nShowZmap = ZSM_SURF ;
m_nShowText = TXT_FILL ;
// PointSize - LineWidth
m_dPointSize = 3 ;
m_dSelPointSize = 5 ;
m_dMarkPointSize = 7 ;
m_dLineWidth = 1 ;
m_dSelLineWidth = 2 ;
m_dMarkLineWidth = 5 ;
m_dGridLineWidth = 1 ;
m_dFrameLineWidth = 2 ;
// Selezione
m_bSelect = false ;
m_nObjFilterForSelect = GEO_ZERODIM | GEO_CURVE | GEO_SURF | GEO_VOLUME | GEO_EXTRA ;
m_Unsel.reserve( 50) ;
m_nSelCurr = GDB_ID_NULL ;
// Snap Punti
m_nLastSnapId = GDB_ID_NULL ;
m_bLastSnapDirOk = false ;
// GeomData
m_pGeomDB = nullptr ;
m_colDef.Set( 0, 0, 0) ;
m_colMark.Set( 255, 255, 0) ;
m_colMark2.Set( 255, 64, 64) ;
m_colSelSurf.Set( 255, 255, 192) ;
// Superfici semitrasparenti
m_vAlphaSurf.reserve( 100) ;
// Extension
SetExtension( BBox3d( -MIN_EXTENSION, -MIN_EXTENSION, -MIN_EXTENSION,
MIN_EXTENSION, MIN_EXTENSION, MIN_EXTENSION)) ;
// Grid
m_bShowGrid = false ;
m_bShowFrame = false ;
m_dSnapStep = 10 ;
m_nMinLineSstep = 1 ;
m_nMajLineSstep = 10 ;
m_nExtSstep = 100 ;
m_dGridMinX = -INFINITO ;
m_dGridMaxX = INFINITO ;
m_dGridMinY = -INFINITO ;
m_dGridMaxY = INFINITO ;
m_colMinLine.Set( 160, 160, 160) ;
m_colMajLine.Set( 160, 160, 160) ;
// Global Frame
m_bShowGlobFrame = false ;
// Direct
m_colorGL.Set( 255, 0, 0) ;
m_bGeoLine = false ;
m_colorGT.Set( 255, 0, 0) ;
m_bGeoTria = false ;
m_bOutlineWR = true ;
m_colorWR.Set( 0, 0, 0) ;
m_bWinRect = false ;
}
//----------------------------------------------------------------------------
Scene::~Scene( void)
{
}
//----------------------------------------------------------------------------
bool
Scene::Init( IGeomDB* pGeomDB)
{
m_pGeomDB = pGeomDB ;
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( GetEGrLogger(), "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( GetEGrLogger(), "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( GetEGrLogger(), "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( GetEGrLogger(), "OpenGL old way rendering !")
// determino la versione di OpenGL
m_nOglVer = 0 ;
const char* p ;
if ( ( p = reinterpret_cast<const char*> ( glGetString( GL_VERSION))) != nullptr) {
string sOglVer = p ;
STRVECTOR vsTok ;
Tokenize( sOglVer, ".", vsTok) ;
if ( vsTok.size() >= 2) {
int nMaj, nMin ;
if ( FromString( vsTok[0], nMaj) && FromString( vsTok[1], nMin))
m_nOglVer = 10 * nMaj + nMin ;
}
}
// 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) const
{
// se RC della scena non è definito, errore
if ( m_hRC == nullptr)
return false ;
// se RC della scena è quello corrente, ok
HGLRC hRC = wglGetCurrentContext() ;
if ( m_hRC == hRC)
return true ;
// impost RC della scena
return ( wglMakeCurrent( m_hDC, m_hRC) != 0) ;
}
//----------------------------------------------------------------------------
string
Scene::GetOpenGLInfo( void) const
{
string sInfo = "OpenGL " ;
if ( MakeCurrent()) {
const char* p ;
if ( ( p = reinterpret_cast<const char*> ( glGetString( GL_VERSION))) != nullptr)
sInfo += p ;
sInfo += ( m_bNewWay ? " (Nw)" : " (Ow)") ;
sInfo += " " ;
if ( ( p = reinterpret_cast<const char*> ( glGetString( GL_VENDOR))) != nullptr)
sInfo += p ;
sInfo += " " ;
if ( ( p = reinterpret_cast<const char*> ( glGetString( GL_RENDERER))) != nullptr)
sInfo += p ;
}
else
sInfo += "ERROR" ;
// reset stato di errore di OpenGL
glGetError() ;
return sInfo ;
}
//----------------------------------------------------------------------------
string
Scene::GetGLSLInfo( void) const
{
string sInfo = "GLSL " ;
if ( MakeCurrent()) {
const char* p ;
if ( ( p = reinterpret_cast<const char*> ( 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) const
{
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::RedrawWindow( void)
{
HWND hWnd = ::WindowFromDC( m_hDC) ;
if ( hWnd == nullptr)
return false ;
return ( ::RedrawWindow( hWnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW) != 0) ;
}
//----------------------------------------------------------------------------
bool
Scene::SetExtension( const BBox3d& b3Ext)
{
if ( b3Ext.IsEmpty())
m_b3ExtWorld.Set( -MIN_EXTENSION, -MIN_EXTENSION, -MIN_EXTENSION,
MIN_EXTENSION, MIN_EXTENSION, MIN_EXTENSION) ;
else
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 ;
if ( ! CalcCameraFrame( frView))
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( abs( ptMin.x), abs( ptMax.x)) ;
double dHalfHeight = COEFF * max( abs( ptMin.y), abs( 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( GetEGrLogger(), sOut.c_str())
}
}
// verifico minimo delle dimensioni
dHalfWidth = max( dHalfWidth, MIN_W_H) ;
dHalfHeight = max( dHalfHeight, MIN_W_H) ;
// 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) ;
if ( m_bOrthographic) {
m_dZNear = - ( ptCenter.z + dExtent) ;
m_dZFar = - ( ptCenter.z - dExtent) ;
}
else {
m_dZNear = PERSPECTIVE_NEAR_PLANE ;
m_dZFar = abs( ptCenter.z - dExtent) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::Resize( 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( GetEGrLogger(), sOut.c_str())
}
// aggiorno
AdjustDimView( m_dHalfWidth, m_dHalfHeight) ;
// ridisegno
return Draw() ;
}
//----------------------------------------------------------------------------
bool
Scene::SetBackground( Color colBackTop, Color colBackBottom)
{
m_colBackTop = colBackTop ;
m_colBackBottom = colBackBottom ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::GetBackground( Color& colBackTop, Color& colBackBottom)
{
colBackTop = m_colBackTop ;
colBackBottom = m_colBackBottom ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::Background( void)
{
// imposto il rendering corrente
if ( ! MakeCurrent())
return false ;
// cancello lo Zbuffer
glClearDepth( 1) ;
glClear( GL_DEPTH_BUFFER_BIT) ;
// se lo sfondo ha un colore uniforme
if ( m_colBackTop == m_colBackBottom) {
// imposto il colore dello sfondo e lo cancello
glClearColor( m_colBackTop.GetRed(), m_colBackTop.GetGreen(), m_colBackTop.GetBlue(), 1) ;
glClear( GL_COLOR_BUFFER_BIT) ;
return true ;
}
// rendo neutre matrici di proiezione e di modello/vista
glMatrixMode( GL_PROJECTION) ;
glLoadIdentity() ;
glMatrixMode( GL_MODELVIEW) ;
glLoadIdentity() ;
// disabilito lo Zdepth
glDisable( GL_DEPTH_TEST) ;
// disabilito illuminazione
glDisable( GL_LIGHTING) ;
// imposto riempimento poligoni
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL) ;
// disegno lo sfondo con due colori
if ( ! m_bNewWay) {
glBegin( GL_TRIANGLE_STRIP) ;
glColor3f( m_colBackBottom.GetRed(), m_colBackBottom.GetGreen(), m_colBackBottom.GetBlue()) ;
glVertex3f( -1, -1, 0.5) ;
glVertex3f( 1, -1, 0.5) ;
glColor3f( m_colBackTop.GetRed(), m_colBackTop.GetGreen(), m_colBackTop.GetBlue()) ;
glVertex3f( -1, 1, 0.5) ;
glVertex3f( 1, 1, 0.5) ;
glEnd() ;
}
else {
unsigned int nVaoId ;
unsigned int nVboId ;
// definizione
glGenVertexArrays( 1, &nVaoId) ;
if ( nVaoId == 0)
return false ;
glBindVertexArray( nVaoId) ;
glGenBuffers( 1, &nVboId) ;
glBindBuffer( GL_ARRAY_BUFFER, nVboId) ;
glBufferData( GL_ARRAY_BUFFER, 8 * SIZEV3F, NULL, GL_STATIC_DRAW) ;
glVertexPointer( 3, GL_FLOAT, 2 * SIZEV3F, ((void*)(0))) ;
glEnableClientState( GL_VERTEX_ARRAY) ;
glColorPointer( 3, GL_FLOAT, 2 * SIZEV3F, ((void*)(1 * SIZEV3F))) ;
glEnableClientState( GL_COLOR_ARRAY) ;
Vert3f v3V ;
Vert3f v3C ;
// bottom left
v3V.Set( -1, -1, 0.5) ;
glBufferSubData( GL_ARRAY_BUFFER, 0 * SIZEV3F, SIZEV3F, &v3V) ;
v3C.Set( m_colBackBottom.GetRed(), m_colBackBottom.GetGreen(), m_colBackBottom.GetBlue()) ;
glBufferSubData( GL_ARRAY_BUFFER, 1 * SIZEV3F, SIZEV3F, &v3C) ;
// bottom right
v3V.Set( 1, -1, 0.5) ;
glBufferSubData( GL_ARRAY_BUFFER, 2 * SIZEV3F, SIZEV3F, &v3V) ;
// v3C constant
glBufferSubData( GL_ARRAY_BUFFER, 3 * SIZEV3F, SIZEV3F, &v3C) ;
// top left
v3V.Set( -1, 1, 0.5) ;
glBufferSubData( GL_ARRAY_BUFFER, 4 * SIZEV3F, SIZEV3F, &v3V) ;
v3C.Set( m_colBackTop.GetRed(), m_colBackTop.GetGreen(), m_colBackTop.GetBlue()) ;
glBufferSubData( GL_ARRAY_BUFFER, 5 * SIZEV3F, SIZEV3F, &v3C) ;
// top right
v3V.Set( 1, 1, 0.5) ;
glBufferSubData( GL_ARRAY_BUFFER, 6 * SIZEV3F, SIZEV3F, &v3V) ;
// v3C constant
glBufferSubData( GL_ARRAY_BUFFER, 7 * SIZEV3F, SIZEV3F, &v3C) ;
// disegno
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4) ;
// cancellazione
glBindBuffer( GL_ARRAY_BUFFER, 0) ;
glDeleteBuffers( 1, &nVboId) ;
glBindVertexArray( 0) ;
glDeleteVertexArrays( 1, &nVaoId) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::Prepare( void)
{
// imposto il rendering corrente
if ( ! MakeCurrent())
return false ;
// eventuale ricalcolo parametri di vista
CalcDirUp() ;
CalcDistCamera() ;
if ( ! m_bOrthographic)
m_bDistOk = false ; // resetto il flag per le prossime operazioni
// imposto matrice di proiezione
glMatrixMode( GL_PROJECTION) ;
glLoadIdentity() ;
if ( m_bSelect) {
// recupero viewport
GLint Viewport[4] ;
glGetIntegerv( GL_VIEWPORT, Viewport) ;
// imposto area di pick
gluPickMatrix( m_ptSelCent.x, ( Viewport[3] - m_ptSelCent.y), m_nSelW, m_nSelH, Viewport) ;
}
if ( m_bOrthographic)
glOrtho( - m_dHalfWidth, m_dHalfWidth, - m_dHalfHeight, m_dHalfHeight, m_dZNear, m_dZFar) ;
else {
// calcolo del fov : se dolly è costante, se zoom standard deve adattarsi alla vista
double dFov = PERSPECTIVE_STD_FOV ;
double dRatio = m_dHalfWidth / m_dHalfHeight ;
if ( m_nPerspZoomType == ZT_STD) {
// verifico che il fov non superi il valore massimo consentito
if ( m_dHalfHeight / m_dDistCamera > PERSPECTIVE_TAN_MAX_FOV) {
dFov = PERSPECTIVE_MAX_FOV ;
// aggiusto i valori di HalfHeight e HalfWidth
m_dHalfHeight = m_dDistCamera * PERSPECTIVE_TAN_MAX_FOV ;
m_dHalfWidth = dRatio * m_dHalfHeight ;
}
else
dFov = 2 * atan2( m_dHalfHeight, m_dDistCamera) * RADTODEG ;
}
gluPerspective( abs( dFov), dRatio, 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( GetEGrLogger(), sOut.c_str())
}
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::Draw( void)
{
return MyDraw( true) ;
}
//----------------------------------------------------------------------------
bool
Scene::MyDraw( bool bSwapBF)
{
// sistemo lo sfondo e lo Zbuffer
if ( ! Background())
return false ;
// imposto la camera
if ( ! Prepare())
return false ;
// imposto l'utilizzo dello Zbuffer
glDepthFunc( GL_LEQUAL) ;
glEnable( GL_DEPTH_TEST) ;
// aggiorno il colore di default
if ( m_pGeomDB != nullptr)
m_pGeomDB->GetDefaultMaterial( m_colDef) ;
// impostazioni dipendenti dalla modalità di visualizzazione
switch ( m_nShowMode) {
case SM_WIREFRAME :
// disabilito illuminazione
glDisable( GL_LIGHTING) ;
// disegno griglia senza illuminazione (già impostato)
DrawGrid() ;
// imposto dati standard per punti e linee
glPointSize( (float) GetPointSize()) ;
glLineWidth( (float) GetLineWidth()) ;
// imposto disegno wireframe anche per poligoni
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE) ;
// disegno le geometrie del DB in una sola passata
DrawGroup( GDB_ID_ROOT, 1, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ;
break ;
case SM_HIDDENLINE :
// disabilito illuminazione
glDisable( GL_LIGHTING) ;
// disegno griglia senza illuminazione (già impostato)
DrawGrid() ;
// imposto dati standard per punti e linee
glPointSize( (float) GetPointSize()) ;
glLineWidth( (float) GetLineWidth()) ;
// disegno le geometrie del DB
// prima passata per superfici solo per aggiornare Zbuffer (poligoni riempiti e offsettati)
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL) ;
glEnable( GL_POLYGON_OFFSET_FILL) ;
glPolygonOffset( 1.0, 1.0) ;
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) ;
DrawGroup( GDB_ID_ROOT, 1, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ;
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ;
glDisable( GL_POLYGON_OFFSET_FILL) ;
// seconda passata per tutto in forma 0dim e curve
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE) ;
DrawGroup( GDB_ID_ROOT, 2, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ;
break ;
case SM_SHADING :
// disegno griglia senza illuminazione
glDisable( GL_LIGHTING) ;
DrawGrid() ;
// imposto dati standard per punti e linee
glPointSize( (float) GetPointSize()) ;
glLineWidth( (float) GetLineWidth()) ;
// imposto disegno shading per poligoni con davanti e dietro diversificati
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL) ;
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) ;
// imposto tipo shading
glShadeModel( GL_SMOOTH) ;
// imposto illuminazione
float LightAmbient[] = { 0.30f, 0.30f, 0.30f, 1.0f} ;
float LightDiff[] = { 0.40f, 0.40f, 0.40f, 1.0f} ;
float LightSpec[] = { 0.10f, 0.10f, 0.10f, 1.0f} ;
float Light0Pos[] = { 0.4f, 0.6f, 0.6f, 0.0f} ;
float Light1Pos[] = { -0.3f, -0.6f, 0.8f, 0.0f} ;
float Light2Pos[] = { -0.5f, 0.2f, -0.3f, 0.0f} ;
glEnable( GL_LIGHT0) ;
glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient) ;
glLightfv( GL_LIGHT0, GL_DIFFUSE, LightDiff) ;
glLightfv( GL_LIGHT0, GL_SPECULAR, LightSpec) ;
glLightfv( GL_LIGHT0, GL_POSITION, Light0Pos) ;
glEnable( GL_LIGHT1) ;
glLightfv( GL_LIGHT1, GL_DIFFUSE, LightDiff) ;
glLightfv( GL_LIGHT1, GL_SPECULAR, LightSpec) ;
glLightfv( GL_LIGHT1, GL_POSITION, Light1Pos) ;
glEnable( GL_LIGHT2) ;
glLightfv( GL_LIGHT2, GL_DIFFUSE, LightDiff) ;
glLightfv( GL_LIGHT2, GL_SPECULAR, LightSpec) ;
glLightfv( GL_LIGHT2, GL_POSITION, Light2Pos) ;
// disegno le geometrie del DB
// annullo vettore superfici traslucide
m_vAlphaSurf.clear() ;
// prima passata per superfici completamente opache con illuminazione abilitata
glEnable( GL_POLYGON_OFFSET_FILL) ;
glPolygonOffset( 0.5, 0.5) ;
glEnable( GL_LIGHTING) ;
DrawGroup( GDB_ID_ROOT, 1, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ;
glDisable( GL_POLYGON_OFFSET_FILL) ;
// seconda passata per 0dim e curve con illuminazione disabilitata
glDisable( GL_LIGHTING) ;
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE) ;
DrawGroup( GDB_ID_ROOT, 2, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ;
// terza passata su vettore di superfici trasparenti con :
// illuminazione abilitata, blend abilitato e Zdepth solo in lettura
if ( m_vAlphaSurf.size() > 0) {
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL) ;
glEnable( GL_POLYGON_OFFSET_FILL) ;
glPolygonOffset( 0.5, 0.5) ;
glEnable( GL_LIGHTING) ;
glEnable( GL_BLEND) ;
glDepthMask( GL_FALSE) ;
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
DrawAlphaSurfVector() ;
m_vAlphaSurf.clear() ;
glDepthMask( GL_TRUE) ;
glDisable( GL_BLEND) ;
glDisable( GL_POLYGON_OFFSET_FILL) ;
}
break ;
}
// disabilito uso Zbuffer e illuminazione
glDisable( GL_DEPTH_TEST) ;
glDisable( GL_LIGHTING) ;
// disegno riferimento globale
DrawGlobFrame() ;
// aggiungo disegni diretti (con poligoni riempiti)
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL) ;
DrawDirect() ;
// aggiorno
glFlush() ;
// verifico presenza errori
GLenum nErr = glGetError() ;
if ( nErr != GL_NO_ERROR) {
string sOut = "Draw OpenGL error " + ToString( (int)nErr) ;
LOG_INFO( GetEGrLogger(), sOut.c_str())
}
// scambio i buffer back e front ( eseguita solo se previsti)
if ( bSwapBF && ! SwapBuffers( m_hDC))
LOG_INFO( GetEGrLogger(), "Draw SwapBuffers error")
return true ;
}
/*------------------------------------------------------------------------------------------*/
bool
Scene::Project( const Point3d& ptWorld, Point3d& ptView) const
{
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) const
{
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) ;
}
//----------------------------------------------------------------------------
bool
Scene::GetPixelZ( const Point3d& ptWin, double& dWinZ)
{
glGetError() ;
// recupero la ViewPort corrente
GLint Viewport[ 4] ;
glGetIntegerv( GL_VIEWPORT, Viewport) ;
// inizializzo i parametri come per la selezione, senza però effettuarla !
m_bSelect = true ;
m_ptSelCent = ptWin ;
m_nSelW = 13 ; // riducibile ...
m_nSelH = 13 ; // riducibile ...
// imposto la pick-matrix e la proiezione ridotta
if ( ! Prepare()) {
m_bSelect = false ;
dWinZ = GetProjectedCenter().z ;
return false ;
}
// forzo rendering opaco per il picking: niente blending, depth write ON
glDisable( GL_LIGHTING) ;
glDisable( GL_BLEND) ;
glEnable( GL_DEPTH_TEST) ;
glDepthMask( GL_TRUE) ;
glClear( GL_DEPTH_BUFFER_BIT) ; // pulizia buffer depth per futura scrittura
// disegno la scena nella viewport ridotta : questo scrive il depth buffer ( se fossi nella vera
// modalità di selezione GL_SELECT non scriverei le depth nel buffer, in quanto non c'è una
// modalità di rendering)
DrawGroup( GDB_ID_ROOT, 1, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ;
glFlush() ; // per sicurezza attendo
// leggo la Z del pixel corrente, le coordinate x e y non cambiano rispetto alla viewport originale
glReadBuffer( GL_FRONT) ;
float dZ ;
bool bOk = true ;
glReadPixels( int( ptWin.x), int( Viewport[3] - ptWin.y), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &dZ) ;
if ( glGetError() == GL_NO_ERROR && dZ > 0.1f && dZ < 0.9f)
dWinZ = dZ ;
else {
bOk = false ;
dWinZ = GetProjectedCenter().z ;
}
// reset dei parametri
m_bSelect = false ;
Prepare() ;
return bOk ;
}
//----------------------------------------------------------------------------
void
Scene::Destroy( void)
{
// cancellazione eventuali ObjEgrGraphics attaccati a oggetti geometrici
DeleteObjGraphicsGroup( GDB_ID_ROOT) ;
// cancellazione textures
if ( ! m_TextMgr.Clear())
LOG_ERROR( GetEGrLogger(), "Error unloading textures from OpenGl") ;
// cancellazione rendering context
wglMakeCurrent( nullptr, nullptr) ;
if ( m_hRC != nullptr) {
wglDeleteContext( m_hRC) ;
m_hRC = nullptr ;
}
}