2016-07-31 11:56:30 +00:00
/// \file glview.cpp
/// \brief OpenGL visualisation. Implementation file.
/// \author smal.root@gmail.com
/// \date 2016
# include "glview.hpp"
// Header files, OpenGL.
# include <GL/glu.h>
// Header files, DevIL.
2016-10-21 10:50:41 +00:00
# include <il.h>
2016-07-31 11:56:30 +00:00
// Header files, Assimp.
# include <assimp/DefaultLogger.hpp>
# ifndef __unused
# define __unused __attribute__((unused))
# endif // __unused
/**********************************/
/********** SHelper_Mesh **********/
/**********************************/
CGLView : : SHelper_Mesh : : SHelper_Mesh ( const size_t pQuantity_Point , const size_t pQuantity_Line , const size_t pQuantity_Triangle , const SBBox & pBBox )
: Quantity_Point ( pQuantity_Point ) , Quantity_Line ( pQuantity_Line ) , Quantity_Triangle ( pQuantity_Triangle ) , BBox ( pBBox )
{
Index_Point = pQuantity_Point ? new GLuint [ pQuantity_Point * 1 ] : nullptr ;
Index_Line = pQuantity_Line ? new GLuint [ pQuantity_Line * 2 ] : nullptr ;
Index_Triangle = pQuantity_Triangle ? new GLuint [ pQuantity_Triangle * 3 ] : nullptr ;
}
CGLView : : SHelper_Mesh : : ~ SHelper_Mesh ( )
{
if ( Index_Point ! = nullptr ) delete [ ] Index_Point ;
if ( Index_Line ! = nullptr ) delete [ ] Index_Line ;
if ( Index_Triangle ! = nullptr ) delete [ ] Index_Triangle ;
}
/**********************************/
/********** SHelper_Mesh **********/
/**********************************/
void CGLView : : SHelper_Camera : : SetDefault ( )
{
Position . Set ( 0 , 0 , 0 ) ;
Target . Set ( 0 , 0 , - 1 ) ;
Rotation_AroundCamera = aiMatrix4x4 ( ) ;
Rotation_Scene = aiMatrix4x4 ( ) ;
Translation_ToScene . Set ( 0 , 0 , 2 ) ;
}
/**********************************/
/************ CGLView *************/
/**********************************/
void CGLView : : Material_Apply ( const aiMaterial * pMaterial )
{
2016-10-21 10:50:41 +00:00
GLfloat tcol [ 4 ] ;
aiColor4D taicol ;
unsigned int max ;
int ret1 , ret2 ;
int texture_index = 0 ;
aiString texture_path ;
2016-07-31 11:56:30 +00:00
2016-10-21 10:50:41 +00:00
auto set_float4 = [ ] ( float f [ 4 ] , float a , float b , float c , float d ) { f [ 0 ] = a , f [ 1 ] = b , f [ 2 ] = c , f [ 3 ] = d ; } ;
auto color4_to_float4 = [ ] ( const aiColor4D * c , float f [ 4 ] ) { f [ 0 ] = c - > r , f [ 1 ] = c - > g , f [ 2 ] = c - > b , f [ 3 ] = c - > a ; } ;
2016-07-31 11:56:30 +00:00
///TODO: cache materials
// Disable color material because glMaterial is used.
glDisable ( GL_COLOR_MATERIAL ) ; ///TODO: cache
// Set texture. If assigned.
if ( AI_SUCCESS = = pMaterial - > GetTexture ( aiTextureType_DIFFUSE , texture_index , & texture_path ) )
{
//bind texture
unsigned int texture_ID = mTexture_IDMap . value ( texture_path . data , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , texture_ID ) ;
}
//
// Set material parameters from scene or default values.
//
// Diffuse
set_float4 ( tcol , 0.8f , 0.8f , 0.8f , 1.0f ) ;
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_DIFFUSE , & taicol ) ) color4_to_float4 ( & taicol , tcol ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_DIFFUSE , tcol ) ;
// Specular
set_float4 ( tcol , 0.0f , 0.0f , 0.0f , 1.0f ) ;
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_SPECULAR , & taicol ) ) color4_to_float4 ( & taicol , tcol ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_SPECULAR , tcol ) ;
// Ambient
set_float4 ( tcol , 0.2f , 0.2f , 0.2f , 1.0f ) ;
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_AMBIENT , & taicol ) ) color4_to_float4 ( & taicol , tcol ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_AMBIENT , tcol ) ;
// Emission
set_float4 ( tcol , 0.0f , 0.0f , 0.0f , 1.0f ) ;
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_EMISSIVE , & taicol ) ) color4_to_float4 ( & taicol , tcol ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_EMISSION , tcol ) ;
// Shininess
float shininess , strength ;
max = 1 ;
ret1 = aiGetMaterialFloatArray ( pMaterial , AI_MATKEY_SHININESS , & shininess , & max ) ;
// Shininess strength
max = 1 ;
ret2 = aiGetMaterialFloatArray ( pMaterial , AI_MATKEY_SHININESS_STRENGTH , & strength , & max ) ;
if ( ( ret1 = = AI_SUCCESS ) & & ( ret2 = = AI_SUCCESS ) )
{
glMaterialf ( GL_FRONT_AND_BACK , GL_SHININESS , shininess * strength ) ; ///TODO: cache
}
else
{
glMaterialf ( GL_FRONT_AND_BACK , GL_SHININESS , 0.0f ) ; ///TODO: cache
set_float4 ( tcol , 0.0f , 0.0f , 0.0f , 0.0f ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_SPECULAR , tcol ) ;
}
// Fill mode
GLenum fill_mode ;
int wireframe ;
max = 1 ;
if ( AI_SUCCESS = = aiGetMaterialIntegerArray ( pMaterial , AI_MATKEY_ENABLE_WIREFRAME , & wireframe , & max ) )
fill_mode = wireframe ? GL_LINE : GL_FILL ;
else
fill_mode = GL_FILL ;
glPolygonMode ( GL_FRONT_AND_BACK , fill_mode ) ; ///TODO: cache
// Fill side
int two_sided ;
max = 1 ;
if ( ( AI_SUCCESS = = aiGetMaterialIntegerArray ( pMaterial , AI_MATKEY_TWOSIDED , & two_sided , & max ) ) & & two_sided ) ///TODO: cache
glDisable ( GL_CULL_FACE ) ;
else
glEnable ( GL_CULL_FACE ) ;
}
void CGLView : : Matrix_NodeToRoot ( const aiNode * pNode , aiMatrix4x4 & pOutMatrix )
{
2017-08-14 20:20:26 +00:00
const aiNode * node_cur ;
std : : list < aiMatrix4x4 > mat_list ;
2016-07-31 11:56:30 +00:00
pOutMatrix = aiMatrix4x4 ( ) ;
// starting walk from current element to root
node_cur = pNode ;
if ( node_cur ! = nullptr )
{
do
{
// if cur_node is group then store group transformation matrix in list.
mat_list . push_back ( node_cur - > mTransformation ) ;
node_cur = node_cur - > mParent ;
} while ( node_cur ! = nullptr ) ;
}
2016-10-21 10:50:41 +00:00
// multiply all matrices in reverse order
for ( std : : list < aiMatrix4x4 > : : reverse_iterator rit = mat_list . rbegin ( ) ; rit ! = mat_list . rend ( ) ; rit + + )
{
pOutMatrix = pOutMatrix * ( * rit ) ;
}
2016-07-31 11:56:30 +00:00
}
void CGLView : : ImportTextures ( const QString & pScenePath )
{
2016-10-21 10:50:41 +00:00
auto LoadTexture = [ & ] ( const QString & pFileName ) - > bool ///TODO: IME texture mode, operation.
{
ILboolean success ;
GLuint id_ogl_texture ; // OpenGL texture ID.
if ( ! pFileName . startsWith ( AI_EMBEDDED_TEXNAME_PREFIX ) )
{
ILuint id_image ; // DevIL image ID.
QString basepath = pScenePath . left ( pScenePath . lastIndexOf ( ' / ' ) + 1 ) ; // path with '/' at the end.
QString fileloc = ( basepath + pFileName ) ;
fileloc . replace ( ' \\ ' , " / " ) ;
ilGenImages ( 1 , & id_image ) ; // Generate DevIL image ID.
ilBindImage ( id_image ) ;
success = ilLoadImage ( fileloc . toLocal8Bit ( ) ) ;
if ( ! success )
{
LogError ( QString ( " Couldn't load Image: %1 " ) . arg ( fileloc ) ) ;
return false ;
}
// Convert every colour component into unsigned byte. If your image contains alpha channel you can replace IL_RGB with IL_RGBA.
success = ilConvertImage ( IL_RGBA , IL_UNSIGNED_BYTE ) ;
if ( ! success )
{
LogError ( " Couldn't convert image. " ) ;
return false ;
}
glGenTextures ( 1 , & id_ogl_texture ) ; // Texture ID generation.
mTexture_IDMap [ pFileName ] = id_ogl_texture ; // save texture ID for filename in map
glBindTexture ( GL_TEXTURE_2D , id_ogl_texture ) ; // Binding of texture ID.
// Redefine standard texture values
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ; // We will use linear interpolation for magnification filter.
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ; // We will use linear interpolation for minifying filter.
glTexImage2D ( GL_TEXTURE_2D , 0 , ilGetInteger ( IL_IMAGE_BPP ) , ilGetInteger ( IL_IMAGE_WIDTH ) , ilGetInteger ( IL_IMAGE_HEIGHT ) , 0 ,
ilGetInteger ( IL_IMAGE_FORMAT ) , GL_UNSIGNED_BYTE , ilGetData ( ) ) ; // Texture specification.
//Cleanup
ilDeleteImages ( 1 , & id_image ) ; // Because we have already copied image data into texture data we can release memory used by image.
}
else
{
struct SPixel_Description
{
const char * FormatHint ;
const GLint Image_InternalFormat ;
const GLint Pixel_Format ;
} ;
constexpr SPixel_Description Pixel_Description [ ] = {
{ " rgba8880 " , GL_RGB , GL_RGB } ,
{ " rgba8888 " , GL_RGBA , GL_RGBA }
} ;
constexpr size_t Pixel_Description_Count = sizeof ( Pixel_Description ) / sizeof ( SPixel_Description ) ;
size_t idx_description ;
// Get texture index.
bool ok ;
size_t idx_texture = pFileName . right ( strlen ( AI_EMBEDDED_TEXNAME_PREFIX ) ) . toULong ( & ok ) ;
if ( ! ok )
{
LogError ( " Can not get index of the embedded texture from path in material. " ) ;
return false ;
}
// Create alias for conveniance.
const aiTexture & als = * mScene - > mTextures [ idx_texture ] ;
if ( als . mHeight = = 0 ) // Compressed texture.
{
LogError ( " IME: compressed embedded textures are not implemented. " ) ;
}
else
{
ok = false ;
for ( size_t idx = 0 ; idx < Pixel_Description_Count ; idx + + )
{
if ( als . CheckFormat ( Pixel_Description [ idx ] . FormatHint ) )
{
idx_description = idx ;
ok = true ;
break ;
}
}
if ( ! ok )
{
LogError ( QString ( " Unsupported format hint for embedded texture: [%1] " ) . arg ( als . achFormatHint ) ) ;
return false ;
}
glGenTextures ( 1 , & id_ogl_texture ) ; // Texture ID generation.
mTexture_IDMap [ pFileName ] = id_ogl_texture ; // save texture ID for filename in map
glBindTexture ( GL_TEXTURE_2D , id_ogl_texture ) ; // Binding of texture ID.
// Redefine standard texture values
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ; // We will use linear interpolation for magnification filter.
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ; // We will use linear interpolation for minifying filter.
// Texture specification.
glTexImage2D ( GL_TEXTURE_2D , 0 , Pixel_Description [ idx_description ] . Image_InternalFormat , als . mWidth , als . mHeight , 0 ,
Pixel_Description [ idx_description ] . Pixel_Format , GL_UNSIGNED_BYTE , ( uint8_t * ) als . pcData ) ;
} // if(als.mHeight == 0) else
} // if(!filename.startsWith(AI_EMBEDDED_TEXNAME_PREFIX)) else
return true ;
} ; // auto LoadTexture = [&](const aiString& pPath)
2016-07-31 11:56:30 +00:00
if ( mScene = = nullptr )
{
LogError ( " Trying to load textures for empty scene. " ) ;
return ;
}
// Before calling ilInit() version should be checked.
if ( ilGetInteger ( IL_VERSION_NUM ) < IL_VERSION )
{
LogError ( " Wrong DevIL version. " ) ;
return ;
}
ilInit ( ) ; // Initialization of DevIL.
//
2016-09-29 14:15:21 +00:00
// Load textures.
2016-07-31 11:56:30 +00:00
//
// Get textures file names and number of textures.
for ( size_t idx_material = 0 ; idx_material < mScene - > mNumMaterials ; idx_material + + )
{
int idx_texture = 0 ;
aiString path ;
do
{
if ( mScene - > mMaterials [ idx_material ] - > GetTexture ( aiTextureType_DIFFUSE , idx_texture , & path ) ! = AI_SUCCESS ) break ;
2016-09-29 14:15:21 +00:00
LoadTexture ( QString ( path . C_Str ( ) ) ) ;
2016-07-31 11:56:30 +00:00
idx_texture + + ;
} while ( true ) ;
2016-09-29 14:15:21 +00:00
} // for(size_t idx_material = 0; idx_material < mScene->mNumMaterials; idx_material++)
2016-07-31 11:56:30 +00:00
// Textures list is empty, exit.
if ( mTexture_IDMap . size ( ) = = 0 )
{
LogInfo ( " No textures for import. " ) ;
return ;
}
}
void CGLView : : BBox_GetForNode ( const aiNode & pNode , const aiMatrix4x4 & pParent_TransformationMatrix , SBBox & pNodeBBox , bool & pFirstAssign )
{
2016-10-22 20:14:01 +00:00
aiMatrix4x4 mat_trans = pParent_TransformationMatrix * pNode . mTransformation ;
2016-07-31 11:56:30 +00:00
// Check if node has meshes
for ( size_t idx_idx_mesh = 0 ; idx_idx_mesh < pNode . mNumMeshes ; idx_idx_mesh + + )
{
size_t idx_mesh ;
SBBox bbox_local ;
aiVector3D bbox_vertices [ 8 ] ;
idx_mesh = pNode . mMeshes [ idx_idx_mesh ] ;
// Get vertices of mesh BBox
BBox_GetVertices ( mHelper_Mesh [ idx_mesh ] - > BBox , bbox_vertices ) ;
// Transform vertices
for ( size_t idx_vert = 0 ; idx_vert < 8 ; idx_vert + + ) bbox_vertices [ idx_vert ] * = mat_trans ;
// And create BBox for transformed mesh
BBox_GetFromVertices ( bbox_vertices , 8 , bbox_local ) ;
if ( ! pFirstAssign )
{
BBox_Extend ( bbox_local , pNodeBBox ) ;
}
else
{
pFirstAssign = false ;
pNodeBBox = bbox_local ;
}
} // for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++)
for ( size_t idx_node = 0 ; idx_node < pNode . mNumChildren ; idx_node + + )
{
BBox_GetForNode ( * pNode . mChildren [ idx_node ] , mat_trans , pNodeBBox , pFirstAssign ) ;
}
}
void CGLView : : BBox_Extend ( const SBBox & pChild , SBBox & pParent )
{
// search minimal...
AssignIfLesser ( & pParent . Minimum . x , pChild . Minimum . x ) ;
AssignIfLesser ( & pParent . Minimum . y , pChild . Minimum . y ) ;
AssignIfLesser ( & pParent . Minimum . z , pChild . Minimum . z ) ;
// and maximal values
AssignIfGreater ( & pParent . Maximum . x , pChild . Maximum . x ) ;
AssignIfGreater ( & pParent . Maximum . y , pChild . Maximum . y ) ;
AssignIfGreater ( & pParent . Maximum . z , pChild . Maximum . z ) ;
}
void CGLView : : BBox_GetVertices ( const SBBox & pBBox , aiVector3D pVertex [ 8 ] )
{
pVertex [ 0 ] = pBBox . Minimum ;
pVertex [ 1 ] . Set ( pBBox . Minimum . x , pBBox . Minimum . y , pBBox . Maximum . z ) ;
pVertex [ 2 ] . Set ( pBBox . Minimum . x , pBBox . Maximum . y , pBBox . Maximum . z ) ;
pVertex [ 3 ] . Set ( pBBox . Minimum . x , pBBox . Maximum . y , pBBox . Minimum . z ) ;
pVertex [ 4 ] . Set ( pBBox . Maximum . x , pBBox . Minimum . y , pBBox . Minimum . z ) ;
pVertex [ 5 ] . Set ( pBBox . Maximum . x , pBBox . Minimum . y , pBBox . Maximum . z ) ;
pVertex [ 6 ] = pBBox . Maximum ;
pVertex [ 7 ] . Set ( pBBox . Maximum . x , pBBox . Maximum . y , pBBox . Minimum . z ) ;
}
void CGLView : : BBox_GetFromVertices ( const aiVector3D * pVertices , const size_t pVerticesQuantity , SBBox & pBBox )
{
if ( pVerticesQuantity = = 0 )
{
pBBox . Maximum . Set ( 0 , 0 , 0 ) ;
pBBox . Minimum . Set ( 0 , 0 , 0 ) ;
return ;
}
// Assign first values.
pBBox . Minimum = pVertices [ 0 ] ;
pBBox . Maximum = pVertices [ 0 ] ;
for ( size_t idx_vert = 1 ; idx_vert < pVerticesQuantity ; idx_vert + + )
{
const GLfloat x = pVertices [ idx_vert ] . x ;
const GLfloat y = pVertices [ idx_vert ] . y ;
const GLfloat z = pVertices [ idx_vert ] . z ;
// search minimal...
AssignIfLesser ( & pBBox . Minimum . x , x ) ;
AssignIfLesser ( & pBBox . Minimum . y , y ) ;
AssignIfLesser ( & pBBox . Minimum . z , z ) ;
// and maximal values
AssignIfGreater ( & pBBox . Maximum . x , x ) ;
AssignIfGreater ( & pBBox . Maximum . y , y ) ;
AssignIfGreater ( & pBBox . Maximum . z , z ) ;
}
}
/********************************************************************/
/************************ Logging functions *************************/
/********************************************************************/
void CGLView : : LogInfo ( const QString & pMessage )
{
Assimp : : DefaultLogger : : get ( ) - > info ( pMessage . toStdString ( ) ) ;
}
void CGLView : : LogError ( const QString & pMessage )
{
Assimp : : DefaultLogger : : get ( ) - > error ( pMessage . toStdString ( ) ) ;
}
/********************************************************************/
/************************** Draw functions **************************/
/********************************************************************/
void CGLView : : Draw_Node ( const aiNode * pNode )
{
2016-10-22 20:14:01 +00:00
aiMatrix4x4 mat_node = pNode - > mTransformation ;
2016-07-31 11:56:30 +00:00
// Apply node transformation matrix.
mat_node . Transpose ( ) ;
glPushMatrix ( ) ;
glMultMatrixf ( ( GLfloat * ) & mat_node ) ;
// Draw all meshes assigned to this node
for ( size_t idx_mesh_arr = 0 ; idx_mesh_arr < pNode - > mNumMeshes ; idx_mesh_arr + + ) Draw_Mesh ( pNode - > mMeshes [ idx_mesh_arr ] ) ;
// Draw all children nodes
for ( size_t idx_node = 0 ; idx_node < pNode - > mNumChildren ; idx_node + + ) Draw_Node ( pNode - > mChildren [ idx_node ] ) ;
// Restore transformation matrix.
glPopMatrix ( ) ;
}
void CGLView : : Draw_Mesh ( const size_t pMesh_Index )
{
// Check argument
if ( pMesh_Index > = mHelper_Mesh_Quantity ) return ;
aiMesh & mesh_cur = * mScene - > mMeshes [ pMesh_Index ] ;
if ( ! mesh_cur . HasPositions ( ) ) return ; // Nothing to draw.
// If mesh use material then apply it
if ( mScene - > HasMaterials ( ) ) Material_Apply ( mScene - > mMaterials [ mesh_cur . mMaterialIndex ] ) ;
//
// Vertices array
//
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glVertexPointer ( 3 , GL_FLOAT , 0 , mesh_cur . mVertices ) ;
if ( mesh_cur . HasVertexColors ( 0 ) )
{
glEnable ( GL_COLOR_MATERIAL ) ; ///TODO: cache
glEnableClientState ( GL_COLOR_ARRAY ) ;
glColorPointer ( 4 , GL_FLOAT , 0 , mesh_cur . mColors [ 0 ] ) ;
}
//
// Texture coordinates array
//
if ( mesh_cur . HasTextureCoords ( 0 ) )
{
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( aiVector3D ) , mesh_cur . mTextureCoords [ 0 ] ) ;
}
//
// Normals array
//
if ( mesh_cur . HasNormals ( ) )
{
glEnableClientState ( GL_NORMAL_ARRAY ) ;
glNormalPointer ( GL_FLOAT , 0 , mesh_cur . mNormals ) ;
}
//
// Draw arrays
//
SHelper_Mesh & helper_cur = * mHelper_Mesh [ pMesh_Index ] ;
if ( helper_cur . Quantity_Triangle > 0 ) glDrawElements ( GL_TRIANGLES , helper_cur . Quantity_Triangle * 3 , GL_UNSIGNED_INT , helper_cur . Index_Triangle ) ;
if ( helper_cur . Quantity_Line > 0 ) glDrawElements ( GL_LINES , helper_cur . Quantity_Line * 2 , GL_UNSIGNED_INT , helper_cur . Index_Line ) ;
if ( helper_cur . Quantity_Point > 0 ) glDrawElements ( GL_POINTS , helper_cur . Quantity_Point , GL_UNSIGNED_INT , helper_cur . Index_Point ) ;
//
// Clean up
//
glDisableClientState ( GL_VERTEX_ARRAY ) ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glDisableClientState ( GL_NORMAL_ARRAY ) ;
}
void CGLView : : Draw_BBox ( const SBBox & pBBox )
{
2016-10-22 20:14:01 +00:00
aiVector3D vertex [ 8 ] ;
2016-07-31 11:56:30 +00:00
BBox_GetVertices ( pBBox , vertex ) ;
// Draw
if ( mLightingEnabled ) glDisable ( GL_LIGHTING ) ; ///TODO: display list
glEnable ( GL_COLOR_MATERIAL ) ;
glBindTexture ( GL_TEXTURE_1D , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glBindTexture ( GL_TEXTURE_3D , 0 ) ;
qglColor ( QColor ( Qt : : white ) ) ;
glBegin ( GL_LINE_STRIP ) ;
glVertex3fv ( & vertex [ 0 ] [ 0 ] ) , glVertex3fv ( & vertex [ 1 ] [ 0 ] ) , glVertex3fv ( & vertex [ 2 ] [ 0 ] ) , glVertex3fv ( & vertex [ 3 ] [ 0 ] ) , glVertex3fv ( & vertex [ 0 ] [ 0 ] ) ; // "Minimum" side.
glVertex3fv ( & vertex [ 4 ] [ 0 ] ) , glVertex3fv ( & vertex [ 5 ] [ 0 ] ) , glVertex3fv ( & vertex [ 6 ] [ 0 ] ) , glVertex3fv ( & vertex [ 7 ] [ 0 ] ) , glVertex3fv ( & vertex [ 4 ] [ 0 ] ) ; // Edge and "maximum" side.
glEnd ( ) ;
glBegin ( GL_LINES ) ;
glVertex3fv ( & vertex [ 1 ] [ 0 ] ) , glVertex3fv ( & vertex [ 5 ] [ 0 ] ) ;
glVertex3fv ( & vertex [ 2 ] [ 0 ] ) , glVertex3fv ( & vertex [ 6 ] [ 0 ] ) ;
glVertex3fv ( & vertex [ 3 ] [ 0 ] ) , glVertex3fv ( & vertex [ 7 ] [ 0 ] ) ;
glEnd ( ) ;
glDisable ( GL_COLOR_MATERIAL ) ;
if ( mLightingEnabled ) glEnable ( GL_LIGHTING ) ;
}
void CGLView : : Enable_Textures ( const bool pEnable )
{
if ( pEnable )
{
glEnable ( GL_TEXTURE_1D ) ;
glEnable ( GL_TEXTURE_2D ) ;
glEnable ( GL_TEXTURE_3D ) ;
}
else
{
glDisable ( GL_TEXTURE_1D ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_TEXTURE_3D ) ;
}
}
/********************************************************************/
/*********************** Overrided functions ************************/
/********************************************************************/
void CGLView : : initializeGL ( )
{
qglClearColor ( Qt : : gray ) ;
glShadeModel ( GL_SMOOTH ) ;
glEnable ( GL_DEPTH_TEST ) ;
glEnable ( GL_NORMALIZE ) ;
glEnable ( GL_TEXTURE_2D ) ;
glColorMaterial ( GL_FRONT_AND_BACK , GL_AMBIENT ) ;
glColorMaterial ( GL_FRONT_AND_BACK , GL_DIFFUSE ) ;
glDisable ( GL_COLOR_MATERIAL ) ;
glHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ;
glEnable ( GL_CULL_FACE ) ;
glCullFace ( GL_BACK ) ;
glFrontFace ( GL_CCW ) ;
}
void CGLView : : resizeGL ( int pWidth , int pHeight )
{
mCamera_Viewport_AspectRatio = ( GLdouble ) pWidth / pHeight ;
glViewport ( 0 , 0 , pWidth , pHeight ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
gluPerspective ( mCamera_FOVY , mCamera_Viewport_AspectRatio , 1.0 , 100000.0 ) ; ///TODO: znear/zfar depend on scene size.
}
2016-11-08 13:53:52 +00:00
void CGLView : : drawCoordSystem ( ) {
glBindTexture ( GL_TEXTURE_1D , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glBindTexture ( GL_TEXTURE_3D , 0 ) ;
glEnable ( GL_COLOR_MATERIAL ) ;
glBegin ( GL_LINES ) ;
// X, -X
qglColor ( QColor ( Qt : : red ) ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 100000.0 , 0.0 , 0.0 ) ;
qglColor ( QColor ( Qt : : cyan ) ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( - 100000.0 , 0.0 , 0.0 ) ;
// Y, -Y
qglColor ( QColor ( Qt : : green ) ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , 100000.0 , 0.0 ) ;
qglColor ( QColor ( Qt : : magenta ) ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , - 100000.0 , 0.0 ) ;
// Z, -Z
qglColor ( QColor ( Qt : : blue ) ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , 0.0 , 100000.0 ) ;
qglColor ( QColor ( Qt : : yellow ) ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , 0.0 , - 100000.0 ) ;
glEnd ( ) ;
}
2016-07-31 11:56:30 +00:00
void CGLView : : paintGL ( )
{
2016-10-22 20:14:01 +00:00
QTime time_paintbegin ;
2016-07-31 11:56:30 +00:00
time_paintbegin = QTime : : currentTime ( ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
// Apply current camera transformations.
glMultMatrixf ( ( GLfloat * ) & mHelper_Camera . Rotation_AroundCamera ) ;
glTranslatef ( - mHelper_Camera . Translation_ToScene . x , - mHelper_Camera . Translation_ToScene . y , - mHelper_Camera . Translation_ToScene . z ) ;
glMultMatrixf ( ( GLfloat * ) & mHelper_Camera . Rotation_Scene ) ;
// Coordinate system
2016-11-08 13:53:52 +00:00
if ( mLightingEnabled ) {
glDisable ( GL_LIGHTING ) ; ///TODO: display list
}
drawCoordSystem ( ) ;
2016-07-31 11:56:30 +00:00
glDisable ( GL_COLOR_MATERIAL ) ;
if ( mLightingEnabled ) glEnable ( GL_LIGHTING ) ;
// Scene
if ( mScene ! = nullptr )
{
Draw_Node ( mScene - > mRootNode ) ;
// Scene BBox
if ( mScene_DrawBBox ) Draw_BBox ( mScene_BBox ) ;
}
emit Paint_Finished ( ( size_t ) time_paintbegin . msecsTo ( QTime : : currentTime ( ) ) , mHelper_Camera . Translation_ToScene . Length ( ) ) ;
}
/********************************************************************/
/********************** Constructor/Destructor **********************/
/********************************************************************/
CGLView : : CGLView ( QWidget * pParent )
: QGLWidget ( QGLFormat ( QGL : : DoubleBuffer | QGL : : DepthBuffer ) , pParent )
{
static_assert ( sizeof ( GLfloat ) = = sizeof ( ai_real ) , " ai_real in Assimp must be equal to GLfloat/float. " ) ; ///TODO: may be templates can be used.
// set initial view
mHelper_CameraDefault . SetDefault ( ) ;
Camera_Set ( 0 ) ;
}
CGLView : : ~ CGLView ( )
{
FreeScene ( ) ;
}
/********************************************************************/
/********************* Scene control functions **********************/
/********************************************************************/
void CGLView : : FreeScene ( )
{
// Set scene to null and after that \ref paintGL will not try to render it.
mScene = nullptr ;
// Clean helper objects.
if ( mHelper_Mesh ! = nullptr )
{
for ( size_t idx_mesh = 0 ; idx_mesh < mHelper_Mesh_Quantity ; idx_mesh + + ) delete mHelper_Mesh [ idx_mesh ] ;
delete [ ] mHelper_Mesh ;
mHelper_Mesh = nullptr ;
}
mHelper_Mesh_Quantity = 0 ;
// Delete textures
const int id_tex_size = mTexture_IDMap . size ( ) ;
if ( id_tex_size )
{
GLuint * id_tex = new GLuint [ id_tex_size ] ;
QMap < QString , GLuint > : : iterator it = mTexture_IDMap . begin ( ) ;
for ( int idx = 0 ; idx < id_tex_size ; idx + + , it + + )
{
id_tex [ idx ] = it . value ( ) ;
}
glDeleteTextures ( id_tex_size , id_tex ) ;
mTexture_IDMap . clear ( ) ;
delete [ ] id_tex ;
}
}
void CGLView : : SetScene ( const aiScene * pScene , const QString & pScenePath )
{
FreeScene ( ) ; // Clear old data
// Why checking here, not at begin of function. Because old scene may not exist at know. So, need cleanup.
if ( pScene = = nullptr ) return ;
mScene = pScene ; // Copy pointer of new scene.
//
// Meshes
//
// Create helper objects for meshes. This allow to render meshes as OpenGL arrays.
if ( mScene - > HasMeshes ( ) )
{
// Create mesh helpers array.
mHelper_Mesh_Quantity = mScene - > mNumMeshes ;
mHelper_Mesh = new SHelper_Mesh * [ mScene - > mNumMeshes ] ;
2017-04-11 20:33:13 +00:00
// Walk through the meshes and extract needed data and, also calculate BBox.
2016-07-31 11:56:30 +00:00
for ( size_t idx_mesh = 0 ; idx_mesh < mScene - > mNumMeshes ; idx_mesh + + )
{
aiMesh & mesh_cur = * mScene - > mMeshes [ idx_mesh ] ;
//
// Calculate BBox
//
SBBox mesh_bbox ;
BBox_GetFromVertices ( mesh_cur . mVertices , mesh_cur . mNumVertices , mesh_bbox ) ;
//
// Create vertices indices arrays splited by primitive type.
//
size_t indcnt_p = 0 ; // points quantity
size_t indcnt_l = 0 ; // lines quantity
size_t indcnt_t = 0 ; // triangles quantity
if ( mesh_cur . HasFaces ( ) )
{
// Usual way: all faces are triangles
if ( mesh_cur . mPrimitiveTypes = = aiPrimitiveType_TRIANGLE )
{
indcnt_t = mesh_cur . mNumFaces ;
}
else
{
// Calculate count of primitives by types.
for ( size_t idx_face = 0 ; idx_face < mesh_cur . mNumFaces ; idx_face + + )
{
if ( mesh_cur . mFaces [ idx_face ] . mNumIndices = = 3 )
indcnt_t + + ;
else if ( mesh_cur . mFaces [ idx_face ] . mNumIndices = = 2 )
indcnt_l + + ;
else if ( mesh_cur . mFaces [ idx_face ] . mNumIndices = = 1 )
indcnt_p + + ;
}
} // if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) else
// Create helper
mHelper_Mesh [ idx_mesh ] = new SHelper_Mesh ( indcnt_p , indcnt_l , indcnt_t , mesh_bbox ) ;
// Fill indices arrays
indcnt_p = 0 , indcnt_l = 0 , indcnt_t = 0 ; // Reuse variables as indices
for ( size_t idx_face = 0 ; idx_face < mesh_cur . mNumFaces ; idx_face + + )
{
if ( mesh_cur . mFaces [ idx_face ] . mNumIndices = = 3 )
{
mHelper_Mesh [ idx_mesh ] - > Index_Triangle [ indcnt_t + + ] = mesh_cur . mFaces [ idx_face ] . mIndices [ 0 ] ;
mHelper_Mesh [ idx_mesh ] - > Index_Triangle [ indcnt_t + + ] = mesh_cur . mFaces [ idx_face ] . mIndices [ 1 ] ;
mHelper_Mesh [ idx_mesh ] - > Index_Triangle [ indcnt_t + + ] = mesh_cur . mFaces [ idx_face ] . mIndices [ 2 ] ;
}
else if ( mesh_cur . mFaces [ idx_face ] . mNumIndices = = 2 )
{
mHelper_Mesh [ idx_mesh ] - > Index_Line [ indcnt_l + + ] = mesh_cur . mFaces [ idx_face ] . mIndices [ 0 ] ;
mHelper_Mesh [ idx_mesh ] - > Index_Line [ indcnt_l + + ] = mesh_cur . mFaces [ idx_face ] . mIndices [ 1 ] ;
}
else if ( mesh_cur . mFaces [ idx_face ] . mNumIndices = = 1 )
{
mHelper_Mesh [ idx_mesh ] - > Index_Point [ indcnt_p + + ] = mesh_cur . mFaces [ idx_face ] . mIndices [ 0 ] ;
}
} // for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++)
} // if(mesh_cur.HasFaces())
else
{
// If mesh has no faces then vertices can be just points set.
indcnt_p = mesh_cur . mNumVertices ;
// Create helper
mHelper_Mesh [ idx_mesh ] = new SHelper_Mesh ( indcnt_p , 0 , 0 , mesh_bbox ) ;
// Fill indices arrays
for ( size_t idx = 0 ; idx < indcnt_p ; idx + + ) mHelper_Mesh [ idx_mesh ] - > Index_Point [ idx ] = idx ;
} // if(mesh_cur.HasFaces()) else
} // for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++)
} // if(mScene->HasMeshes())
//
// Scene BBox
//
2017-04-11 20:33:13 +00:00
// For calculating right BBox we must walk through all nodes and apply transformation to meshes BBoxes
2016-07-31 11:56:30 +00:00
if ( mHelper_Mesh_Quantity > 0 )
{
bool first_assign = true ;
aiMatrix4x4 mat_root ;
BBox_GetForNode ( * mScene - > mRootNode , mat_root , mScene_BBox , first_assign ) ;
mScene_Center = mScene_BBox . Maximum + mScene_BBox . Minimum ;
mScene_Center / = 2 ;
}
else
{
mScene_BBox = { { 0 , 0 , 0 } , { 0 , 0 , 0 } } ;
mScene_Center = { 0 , 0 , 0 } ;
} // if(mHelper_Mesh_Count > 0) else
//
// Textures
//
ImportTextures ( pScenePath ) ;
//
// Light sources
//
Lighting_Enable ( ) ;
// If scene has no lights then enable default
if ( ! mScene - > HasLights ( ) )
{
const GLfloat col_amb [ 4 ] = { 0.2 , 0.2 , 0.2 , 1.0 } ;
SLightParameters lp ;
lp . Type = aiLightSource_POINT ;
lp . Ambient . r = col_amb [ 0 ] , lp . Ambient . g = col_amb [ 1 ] , lp . Ambient . b = col_amb [ 2 ] , lp . Ambient . a = col_amb [ 3 ] ;
lp . Diffuse = { 1.0 , 1.0 , 1.0 , 1.0 } ;
lp . Specular = lp . Diffuse ;
lp . For . Point . Position = mScene_Center ;
lp . For . Point . Attenuation_Constant = 1 ;
lp . For . Point . Attenuation_Linear = 0 ;
lp . For . Point . Attenuation_Quadratic = 0 ;
glLightModelfv ( GL_LIGHT_MODEL_AMBIENT , col_amb ) ;
Lighting_EditSource ( 0 , lp ) ;
emit SceneObject_LightSource ( " _default " ) ; // Light source will be enabled in signal handler.
}
else
{
for ( size_t idx_light = 0 ; idx_light < mScene - > mNumLights ; idx_light + + )
{
SLightParameters lp ;
QString name ;
const aiLight & light_cur = * mScene - > mLights [ idx_light ] ;
auto col3_to_col4 = [ ] ( const aiColor3D & pCol3 ) - > aiColor4D { return aiColor4D ( pCol3 . r , pCol3 . g , pCol3 . b , 1.0 ) ; } ;
///TODO: find light source node and apply all transformations
// General properties
name = light_cur . mName . C_Str ( ) ;
lp . Ambient = col3_to_col4 ( light_cur . mColorAmbient ) ;
lp . Diffuse = col3_to_col4 ( light_cur . mColorDiffuse ) ;
lp . Specular = col3_to_col4 ( light_cur . mColorSpecular ) ;
lp . Type = light_cur . mType ;
// Depend on type properties
switch ( light_cur . mType )
{
case aiLightSource_DIRECTIONAL :
lp . For . Directional . Direction = light_cur . mDirection ;
break ;
case aiLightSource_POINT :
lp . For . Point . Position = light_cur . mPosition ;
lp . For . Point . Attenuation_Constant = light_cur . mAttenuationConstant ;
lp . For . Point . Attenuation_Linear = light_cur . mAttenuationLinear ;
lp . For . Point . Attenuation_Quadratic = light_cur . mAttenuationQuadratic ;
break ;
case aiLightSource_SPOT :
lp . For . Spot . Position = light_cur . mPosition ;
lp . For . Spot . Direction = light_cur . mDirection ;
lp . For . Spot . Attenuation_Constant = light_cur . mAttenuationConstant ;
lp . For . Spot . Attenuation_Linear = light_cur . mAttenuationLinear ;
lp . For . Spot . Attenuation_Quadratic = light_cur . mAttenuationQuadratic ;
lp . For . Spot . CutOff = light_cur . mAngleOuterCone ;
break ;
case aiLightSource_AMBIENT :
lp . For . Point . Position = light_cur . mPosition , lp . For . Point . Attenuation_Constant = 1 , lp . For . Point . Attenuation_Linear = 0 , lp . For . Point . Attenuation_Quadratic = 0 ;
name . append ( " _unsup_ambient " ) ;
break ;
case aiLightSource_AREA :
lp . For . Point . Position = light_cur . mPosition , lp . For . Point . Attenuation_Constant = 1 , lp . For . Point . Attenuation_Linear = 0 , lp . For . Point . Attenuation_Quadratic = 0 ;
name . append ( " _unsup_area " ) ;
break ;
case aiLightSource_UNDEFINED :
lp . For . Point . Position = light_cur . mPosition , lp . For . Point . Attenuation_Constant = 1 , lp . For . Point . Attenuation_Linear = 0 , lp . For . Point . Attenuation_Quadratic = 0 ;
name . append ( " _unsup_undefined " ) ;
break ;
default :
lp . For . Point . Position = light_cur . mPosition , lp . For . Point . Attenuation_Constant = 1 , lp . For . Point . Attenuation_Linear = 0 , lp . For . Point . Attenuation_Quadratic = 0 ;
name . append ( " _unsupported_invalid " ) ;
break ;
} // switch(light_cur.mType)
// Add light source
if ( name . isEmpty ( ) ) name + = QString ( " %1 " ) . arg ( idx_light ) ; // Use index if name is empty.
Lighting_EditSource ( idx_light , lp ) ;
emit SceneObject_LightSource ( name ) ; // Light source will be enabled in signal handler.
} // for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++)
} // if(!mScene->HasLights()) else
//
// Cameras
//
if ( ! mScene - > HasCameras ( ) )
{
mCamera_DefaultAdded = true ;
mHelper_CameraDefault . SetDefault ( ) ;
// Calculate distance from camera to scene. Distance must be enoguh for that viewport contain whole scene.
const GLfloat tg_angle = tan ( mCamera_FOVY / 2 ) ;
GLfloat val_x = ( ( mScene_BBox . Maximum . x - mScene_BBox . Minimum . x ) / 2 ) / ( mCamera_Viewport_AspectRatio * tg_angle ) ;
GLfloat val_y = ( ( mScene_BBox . Maximum . y - mScene_BBox . Minimum . y ) / 2 ) / tg_angle ;
GLfloat val_step = val_x ;
AssignIfGreater ( val_step , val_y ) ;
mHelper_CameraDefault . Translation_ToScene . Set ( mScene_Center . x , mScene_Center . y , val_step + mScene_BBox . Maximum . z ) ;
emit SceneObject_Camera ( " _default " ) ;
}
else
{
mCamera_DefaultAdded = false ;
for ( size_t idx_cam = 0 ; idx_cam < mScene - > mNumCameras ; idx_cam + + )
{
emit SceneObject_Camera ( mScene - > mCameras [ idx_cam ] - > mName . C_Str ( ) ) ;
}
} // if(!mScene->HasCameras()) else
}
/********************************************************************/
/******************** Lighting control functions ********************/
/********************************************************************/
void CGLView : : Lighting_Enable ( )
{
mLightingEnabled = true ;
glEnable ( GL_LIGHTING ) ;
}
void CGLView : : Lighting_Disable ( )
{
glDisable ( GL_LIGHTING ) ;
mLightingEnabled = false ;
}
void CGLView : : Lighting_EditSource ( const size_t pLightNumber , const SLightParameters & pLightParameters )
{
const size_t light_num = GL_LIGHT0 + pLightNumber ;
GLfloat farr [ 4 ] ;
if ( pLightNumber > = GL_MAX_LIGHTS ) return ; ///TODO: return value;
glLightfv ( light_num , GL_AMBIENT , & pLightParameters . Ambient . r ) ; // Ambient color
glLightfv ( light_num , GL_DIFFUSE , & pLightParameters . Diffuse . r ) ; // Diffuse color
glLightfv ( light_num , GL_SPECULAR , & pLightParameters . Specular . r ) ; // Specular color
// Other parameters
switch ( pLightParameters . Type )
{
case aiLightSource_DIRECTIONAL :
// Direction
farr [ 0 ] = pLightParameters . For . Directional . Direction . x , farr [ 2 ] = pLightParameters . For . Directional . Direction . y ;
farr [ 2 ] = pLightParameters . For . Directional . Direction . z ; farr [ 3 ] = 0 ;
glLightfv ( light_num , GL_POSITION , farr ) ;
break ;
case aiLightSource_POINT :
// Position
farr [ 0 ] = pLightParameters . For . Point . Position . x , farr [ 2 ] = pLightParameters . For . Point . Position . y ;
farr [ 2 ] = pLightParameters . For . Point . Position . z ; farr [ 3 ] = 1 ;
glLightfv ( light_num , GL_POSITION , farr ) ;
// Attenuation
glLightf ( light_num , GL_CONSTANT_ATTENUATION , pLightParameters . For . Point . Attenuation_Constant ) ;
glLightf ( light_num , GL_LINEAR_ATTENUATION , pLightParameters . For . Point . Attenuation_Linear ) ;
glLightf ( light_num , GL_QUADRATIC_ATTENUATION , pLightParameters . For . Point . Attenuation_Quadratic ) ;
glLightf ( light_num , GL_SPOT_CUTOFF , 180.0 ) ;
break ;
case aiLightSource_SPOT :
// Position
farr [ 0 ] = pLightParameters . For . Spot . Position . x , farr [ 2 ] = pLightParameters . For . Spot . Position . y , farr [ 2 ] = pLightParameters . For . Spot . Position . z ; farr [ 3 ] = 1 ;
glLightfv ( light_num , GL_POSITION , farr ) ;
// Attenuation
glLightf ( light_num , GL_CONSTANT_ATTENUATION , pLightParameters . For . Spot . Attenuation_Constant ) ;
glLightf ( light_num , GL_LINEAR_ATTENUATION , pLightParameters . For . Spot . Attenuation_Linear ) ;
glLightf ( light_num , GL_QUADRATIC_ATTENUATION , pLightParameters . For . Spot . Attenuation_Quadratic ) ;
// Spot specific
farr [ 0 ] = pLightParameters . For . Spot . Direction . x , farr [ 2 ] = pLightParameters . For . Spot . Direction . y , farr [ 2 ] = pLightParameters . For . Spot . Direction . z ; farr [ 3 ] = 0 ;
glLightfv ( light_num , GL_SPOT_DIRECTION , farr ) ;
glLightf ( light_num , GL_SPOT_CUTOFF , pLightParameters . For . Spot . CutOff ) ;
break ;
default : // For unknown light source types use point source.
// Position
farr [ 0 ] = pLightParameters . For . Point . Position . x , farr [ 2 ] = pLightParameters . For . Point . Position . y ;
farr [ 2 ] = pLightParameters . For . Point . Position . z ; farr [ 3 ] = 1 ;
glLightfv ( light_num , GL_POSITION , farr ) ;
// Attenuation
glLightf ( light_num , GL_CONSTANT_ATTENUATION , 1 ) ;
glLightf ( light_num , GL_LINEAR_ATTENUATION , 0 ) ;
glLightf ( light_num , GL_QUADRATIC_ATTENUATION , 0 ) ;
glLightf ( light_num , GL_SPOT_CUTOFF , 180.0 ) ;
break ;
} // switch(pLightParameters.Type)
}
void CGLView : : Lighting_EnableSource ( const size_t pLightNumber )
{
if ( pLightNumber > = GL_MAX_LIGHTS ) return ; ///TODO: return value;
glEnable ( GL_LIGHT0 + pLightNumber ) ;
}
void CGLView : : Lighting_DisableSource ( const size_t pLightNumber )
{
if ( pLightNumber > = GL_MAX_LIGHTS ) return ; ///TODO: return value;
glDisable ( GL_LIGHT0 + pLightNumber ) ;
}
/********************************************************************/
/******************** Cameras control functions *********************/
/********************************************************************/
void CGLView : : Camera_Set ( const size_t pCameraNumber )
{
2016-10-22 20:14:01 +00:00
SHelper_Camera & hcam = mHelper_Camera ; // reference with short name for conveniance.
aiVector3D up ;
2016-07-31 11:56:30 +00:00
if ( mCamera_DefaultAdded | | ( pCameraNumber > = mScene - > mNumCameras ) ) // If default camera used then 'pCameraNumber' doesn't matter.
{
// Transformation parameters
hcam = mHelper_CameraDefault ;
up . Set ( 0 , 1 , 0 ) ;
}
else
{
const aiCamera & camera_cur = * mScene - > mCameras [ pCameraNumber ] ;
const aiNode * camera_node ;
aiMatrix4x4 camera_mat ;
aiQuaternion camera_quat_rot ;
aiVector3D camera_tr ;
up = camera_cur . mUp ;
//
// Try to get real coordinates of the camera.
//
// Find node
camera_node = mScene - > mRootNode - > FindNode ( camera_cur . mName ) ;
if ( camera_node ! = nullptr ) Matrix_NodeToRoot ( camera_node , camera_mat ) ;
hcam . Position = camera_cur . mLookAt ;
hcam . Target = camera_cur . mPosition ;
hcam . Rotation_AroundCamera = aiMatrix4x4 ( camera_quat_rot . GetMatrix ( ) ) ;
hcam . Rotation_AroundCamera . Transpose ( ) ;
// get components of transformation matrix.
camera_mat . DecomposeNoScaling ( camera_quat_rot , camera_tr ) ;
hcam . Rotation_Scene = aiMatrix4x4 ( ) ;
hcam . Translation_ToScene = camera_tr ;
}
// Load identity matrix - travel to world begin.
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
// Set camera and update picture
gluLookAt ( hcam . Position . x , hcam . Position . y , hcam . Position . z , hcam . Target . x , hcam . Target . y , hcam . Target . z , up . x , up . y , up . z ) ;
}
void CGLView : : Camera_RotateScene ( const GLfloat pAngle_X , const GLfloat pAngle_Y , const GLfloat pAngle_Z )
{
auto deg2rad = [ ] ( const GLfloat pDegree ) - > GLfloat { return pDegree * M_PI / 180.0 ; } ;
aiMatrix4x4 mat_rot ;
mat_rot . FromEulerAnglesXYZ ( deg2rad ( pAngle_X ) , deg2rad ( pAngle_Y ) , deg2rad ( pAngle_Z ) ) ;
mHelper_Camera . Rotation_Scene * = mat_rot ;
}
void CGLView : : Camera_Rotate ( const GLfloat pAngle_X , const GLfloat pAngle_Y , const GLfloat pAngle_Z )
{
auto deg2rad = [ ] ( const GLfloat pDegree ) - > GLfloat { return pDegree * M_PI / 180.0 ; } ;
aiMatrix4x4 mat_rot ;
mat_rot . FromEulerAnglesXYZ ( deg2rad ( pAngle_X ) , deg2rad ( pAngle_Y ) , deg2rad ( pAngle_Z ) ) ;
mHelper_Camera . Rotation_AroundCamera * = mat_rot ;
}
void CGLView : : Camera_Translate ( const GLfloat pTranslate_X , const GLfloat pTranslate_Y , const GLfloat pTranslate_Z )
{
aiVector3D vect_tr ( pTranslate_X , pTranslate_Y , pTranslate_Z ) ;
vect_tr * = mHelper_Camera . Rotation_AroundCamera ;
mHelper_Camera . Translation_ToScene + = vect_tr ;
}