2018-08-19 14:51:47 +00:00
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Open Asset Import Library ( assimp )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Copyright ( c ) 2006 - 2018 , assimp team
All rights reserved .
Redistribution and use of this software in source and binary forms ,
with or without modification , are permitted provided that the following
conditions are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the
following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the
following disclaimer in the documentation and / or other
materials provided with the distribution .
* Neither the name of the assimp team , nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2016-07-31 11:56:30 +00:00
# include "glview.hpp"
2018-05-25 18:19:06 +00:00
// Header files, Qt.
# include <QTime>
2016-07-31 11:56:30 +00:00
// Header files, OpenGL.
2017-08-30 15:18:36 +00:00
# if defined(__APPLE__)
# include <OpenGL / glu.h>
# else
# include <GL / glu.h>
# endif
2016-07-31 11:56:30 +00:00
// Header files, DevIL.
// Header files, Assimp.
# include <assimp/DefaultLogger.hpp>
2018-08-18 09:07:12 +00:00
# define STB_IMAGE_IMPLEMENTATION
2019-02-07 16:09:05 +00:00
# include "contrib/stb_image/stb_image.h"
2016-07-31 11:56:30 +00:00
CGLView : : SHelper_Mesh : : SHelper_Mesh ( const size_t pQuantity_Point , const size_t pQuantity_Line , const size_t pQuantity_Triangle , const SBBox & pBBox )
2018-08-18 09:07:12 +00:00
: Quantity_Point ( pQuantity_Point )
, Quantity_Line ( pQuantity_Line )
, Quantity_Triangle ( pQuantity_Triangle )
, BBox ( pBBox ) {
2016-07-31 11:56:30 +00:00
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 ;
}
2018-08-19 14:51:47 +00:00
CGLView : : SHelper_Mesh : : ~ SHelper_Mesh ( ) {
delete [ ] Index_Point ;
delete [ ] Index_Line ;
delete [ ] Index_Triangle ;
2016-07-31 11:56:30 +00:00
}
2018-08-19 19:27:08 +00:00
void CGLView : : SHelper_Camera : : SetDefault ( ) {
2016-07-31 11:56:30 +00:00
Position . Set ( 0 , 0 , 0 ) ;
Target . Set ( 0 , 0 , - 1 ) ;
Rotation_AroundCamera = aiMatrix4x4 ( ) ;
Rotation_Scene = aiMatrix4x4 ( ) ;
Translation_ToScene . Set ( 0 , 0 , 2 ) ;
}
2018-08-18 09:07:12 +00:00
static void 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 ;
}
static void 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 ;
}
2018-08-19 19:27:08 +00:00
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
///TODO: cache materials
// Disable color material because glMaterial is used.
glDisable ( GL_COLOR_MATERIAL ) ; ///TODO: cache
2018-08-19 19:27:08 +00:00
// Set texture. If assigned.
if ( AI_SUCCESS = = pMaterial - > GetTexture ( aiTextureType_DIFFUSE , texture_index , & texture_path ) ) {
2016-07-31 11:56:30 +00:00
//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 ) ;
2018-08-19 19:27:08 +00:00
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_DIFFUSE , & taicol ) ) {
color4_to_float4 ( & taicol , tcol ) ;
}
2016-07-31 11:56:30 +00:00
glMaterialfv ( GL_FRONT_AND_BACK , GL_DIFFUSE , tcol ) ;
2018-08-19 19:27:08 +00:00
// Specular
2016-07-31 11:56:30 +00:00
set_float4 ( tcol , 0.0f , 0.0f , 0.0f , 1.0f ) ;
2018-08-19 19:27:08 +00:00
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_SPECULAR , & taicol ) ) {
color4_to_float4 ( & taicol , tcol ) ;
}
2016-07-31 11:56:30 +00:00
glMaterialfv ( GL_FRONT_AND_BACK , GL_SPECULAR , tcol ) ;
// Ambient
set_float4 ( tcol , 0.2f , 0.2f , 0.2f , 1.0f ) ;
2018-08-19 19:27:08 +00:00
if ( AI_SUCCESS = = aiGetMaterialColor ( pMaterial , AI_MATKEY_COLOR_AMBIENT , & taicol ) ) {
color4_to_float4 ( & taicol , tcol ) ;
}
2016-07-31 11:56:30 +00:00
glMaterialfv ( GL_FRONT_AND_BACK , GL_AMBIENT , tcol ) ;
2018-08-19 19:27:08 +00:00
// Emission
2016-07-31 11:56:30 +00:00
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
2018-05-25 18:19:06 +00:00
ai_real shininess , strength ;
2016-07-31 11:56:30 +00:00
max = 1 ;
ret1 = aiGetMaterialFloatArray ( pMaterial , AI_MATKEY_SHININESS , & shininess , & max ) ;
// Shininess strength
max = 1 ;
ret2 = aiGetMaterialFloatArray ( pMaterial , AI_MATKEY_SHININESS_STRENGTH , & strength , & max ) ;
2018-08-19 19:27:08 +00:00
if ( ( ret1 = = AI_SUCCESS ) & & ( ret2 = = AI_SUCCESS ) ) {
2016-07-31 11:56:30 +00:00
glMaterialf ( GL_FRONT_AND_BACK , GL_SHININESS , shininess * strength ) ; ///TODO: cache
2018-08-19 19:27:08 +00:00
} else {
2016-07-31 11:56:30 +00:00
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
2019-09-03 06:02:56 +00:00
for ( std : : list < aiMatrix4x4 > : : reverse_iterator rit = mat_list . rbegin ( ) ; rit ! = mat_list . rend ( ) ; + + rit )
2016-10-21 10:50:41 +00:00
{
pOutMatrix = pOutMatrix * ( * rit ) ;
}
2016-07-31 11:56:30 +00:00
}
2018-08-19 14:51:47 +00:00
void CGLView : : ImportTextures ( const QString & scenePath ) {
2016-10-21 10:50:41 +00:00
auto LoadTexture = [ & ] ( const QString & pFileName ) - > bool ///TODO: IME texture mode, operation.
{
GLuint id_ogl_texture ; // OpenGL texture ID.
if ( ! pFileName . startsWith ( AI_EMBEDDED_TEXNAME_PREFIX ) )
{
2018-08-19 14:51:47 +00:00
QString basepath = scenePath . left ( scenePath . lastIndexOf ( ' / ' ) + 1 ) ; // path with '/' at the end.
2016-10-21 10:50:41 +00:00
QString fileloc = ( basepath + pFileName ) ;
fileloc . replace ( ' \\ ' , " / " ) ;
2018-08-18 09:07:12 +00:00
int x , y , n ;
unsigned char * data = stbi_load ( fileloc . toLocal8Bit ( ) , & x , & y , & n , STBI_rgb_alpha ) ;
2018-08-19 14:51:47 +00:00
if ( nullptr = = data ) {
2016-10-21 10:50:41 +00:00
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.
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.
2018-08-18 09:07:12 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , n , x , y , 0 , GL_RGBA_INTEGER , GL_UNSIGNED_BYTE , data ) ; // Texture specification.
2019-02-07 16:09:05 +00:00
stbi_image_free ( data ) ;
2018-08-18 09:07:12 +00:00
// Cleanup
2016-10-21 10:50:41 +00:00
}
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 ;
}
//
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.
2018-08-18 09:07:12 +00:00
for ( size_t idx_material = 0 ; idx_material < mScene - > mNumMaterials ; idx_material + + ) {
2016-07-31 11:56:30 +00:00
int idx_texture = 0 ;
aiString path ;
2018-08-18 09:07:12 +00:00
do {
if ( mScene - > mMaterials [ idx_material ] - > GetTexture ( aiTextureType_DIFFUSE , idx_texture , & path ) ! = AI_SUCCESS ) {
break ;
}
2016-07-31 11:56:30 +00:00
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.
2018-08-18 09:07:12 +00:00
if ( mTexture_IDMap . empty ( ) ) {
2016-07-31 11:56:30 +00:00
LogInfo ( " No textures for import. " ) ;
}
}
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 + + )
{
2018-05-25 18:19:06 +00:00
const ai_real x = pVertices [ idx_vert ] . x ;
const ai_real y = pVertices [ idx_vert ] . y ;
const ai_real z = pVertices [ idx_vert ] . z ;
2016-07-31 11:56:30 +00:00
// 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 ) ;
}
}
2018-08-19 19:27:08 +00:00
void CGLView : : LogInfo ( const QString & pMessage ) {
2016-07-31 11:56:30 +00:00
Assimp : : DefaultLogger : : get ( ) - > info ( pMessage . toStdString ( ) ) ;
}
2018-08-19 19:27:08 +00:00
void CGLView : : LogError ( const QString & pMessage ) {
2016-07-31 11:56:30 +00:00
Assimp : : DefaultLogger : : get ( ) - > error ( pMessage . toStdString ( ) ) ;
}
2018-08-19 19:27:08 +00:00
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 ( ) ;
2018-08-18 09:07:12 +00:00
# ifdef ASSIMP_DOUBLE_PRECISION
2018-05-25 18:19:06 +00:00
glMultMatrixd ( ( GLdouble * ) mat_node [ 0 ] ) ;
# else
2016-07-31 11:56:30 +00:00
glMultMatrixf ( ( GLfloat * ) & mat_node ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
// 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 ) ;
2018-05-25 18:19:06 +00:00
# if ASSIMP_DOUBLE_PRECISION
glVertexPointer ( 3 , GL_DOUBLE , 0 , mesh_cur . mVertices ) ;
# else
2016-07-31 11:56:30 +00:00
glVertexPointer ( 3 , GL_FLOAT , 0 , mesh_cur . mVertices ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
if ( mesh_cur . HasVertexColors ( 0 ) )
{
glEnable ( GL_COLOR_MATERIAL ) ; ///TODO: cache
glEnableClientState ( GL_COLOR_ARRAY ) ;
2018-08-18 09:07:12 +00:00
# ifdef ASSIMP_DOUBLE_PRECISION
2018-05-25 18:19:06 +00:00
glColorPointer ( 4 , GL_DOUBLE , 0 , mesh_cur . mColors [ 0 ] ) ;
# else
2016-07-31 11:56:30 +00:00
glColorPointer ( 4 , GL_FLOAT , 0 , mesh_cur . mColors [ 0 ] ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
}
//
// Texture coordinates array
//
if ( mesh_cur . HasTextureCoords ( 0 ) )
{
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
2018-08-18 09:07:12 +00:00
# ifdef ASSIMP_DOUBLE_PRECISION
2018-05-25 18:19:06 +00:00
glTexCoordPointer ( 2 , GL_DOUBLE , sizeof ( aiVector3D ) , mesh_cur . mTextureCoords [ 0 ] ) ;
# else
2016-07-31 11:56:30 +00:00
glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( aiVector3D ) , mesh_cur . mTextureCoords [ 0 ] ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
}
//
// Normals array
//
if ( mesh_cur . HasNormals ( ) )
{
glEnableClientState ( GL_NORMAL_ARRAY ) ;
2018-08-18 09:07:12 +00:00
# ifdef ASSIMP_DOUBLE_PRECISION
2018-05-25 18:19:06 +00:00
glNormalPointer ( GL_DOUBLE , 0 , mesh_cur . mNormals ) ;
# else
2016-07-31 11:56:30 +00:00
glNormalPointer ( GL_FLOAT , 0 , mesh_cur . mNormals ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
}
//
// 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 ) ;
2018-05-25 18:19:06 +00:00
const QColor c_w ( Qt : : white ) ;
glColor3f ( c_w . redF ( ) , c_w . greenF ( ) , c_w . blueF ( ) ) ;
2016-07-31 11:56:30 +00:00
glBegin ( GL_LINE_STRIP ) ;
2018-08-18 09:07:12 +00:00
# ifdef ASSIMP_DOUBLE_PRECISION
2018-05-25 18:19:06 +00:00
glVertex3dv ( & vertex [ 0 ] [ 0 ] ) , glVertex3dv ( & vertex [ 1 ] [ 0 ] ) , glVertex3dv ( & vertex [ 2 ] [ 0 ] ) , glVertex3dv ( & vertex [ 3 ] [ 0 ] ) , glVertex3dv ( & vertex [ 0 ] [ 0 ] ) ; // "Minimum" side.
glVertex3dv ( & vertex [ 4 ] [ 0 ] ) , glVertex3dv ( & vertex [ 5 ] [ 0 ] ) , glVertex3dv ( & vertex [ 6 ] [ 0 ] ) , glVertex3dv ( & vertex [ 7 ] [ 0 ] ) , glVertex3dv ( & vertex [ 4 ] [ 0 ] ) ; // Edge and "maximum" side.
# else
2016-07-31 11:56:30 +00:00
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.
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
glEnd ( ) ;
2018-05-25 18:19:06 +00:00
2016-07-31 11:56:30 +00:00
glBegin ( GL_LINES ) ;
2018-08-18 09:07:12 +00:00
# ifdef ASSIMP_DOUBLE_PRECISION
2018-05-25 18:19:06 +00:00
glVertex3dv ( & vertex [ 1 ] [ 0 ] ) , glVertex3dv ( & vertex [ 5 ] [ 0 ] ) ;
glVertex3dv ( & vertex [ 2 ] [ 0 ] ) , glVertex3dv ( & vertex [ 6 ] [ 0 ] ) ;
glVertex3dv ( & vertex [ 3 ] [ 0 ] ) , glVertex3dv ( & vertex [ 7 ] [ 0 ] ) ;
# else
2016-07-31 11:56:30 +00:00
glVertex3fv ( & vertex [ 1 ] [ 0 ] ) , glVertex3fv ( & vertex [ 5 ] [ 0 ] ) ;
glVertex3fv ( & vertex [ 2 ] [ 0 ] ) , glVertex3fv ( & vertex [ 6 ] [ 0 ] ) ;
glVertex3fv ( & vertex [ 3 ] [ 0 ] ) , glVertex3fv ( & vertex [ 7 ] [ 0 ] ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
glEnd ( ) ;
glDisable ( GL_COLOR_MATERIAL ) ;
if ( mLightingEnabled ) glEnable ( GL_LIGHTING ) ;
2018-05-25 18:19:06 +00:00
2016-07-31 11:56:30 +00:00
}
2018-08-19 19:27:08 +00:00
void CGLView : : Enable_Textures ( const bool pEnable ) {
if ( pEnable ) {
2016-07-31 11:56:30 +00:00
glEnable ( GL_TEXTURE_1D ) ;
glEnable ( GL_TEXTURE_2D ) ;
glEnable ( GL_TEXTURE_3D ) ;
2018-08-19 19:27:08 +00:00
} else {
2016-07-31 11:56:30 +00:00
glDisable ( GL_TEXTURE_1D ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_TEXTURE_3D ) ;
}
}
2018-08-19 19:27:08 +00:00
void CGLView : : initializeGL ( ) {
2018-05-25 18:19:06 +00:00
mGLContext_Current = true ;
initializeOpenGLFunctions ( ) ;
glClearColor ( 0.5f , 0.5f , 0.5f , 1.0f ) ;
2016-07-31 11:56:30 +00:00
glShadeModel ( GL_SMOOTH ) ;
glEnable ( GL_DEPTH_TEST ) ;
glEnable ( GL_NORMALIZE ) ;
glEnable ( GL_TEXTURE_2D ) ;
2018-08-19 19:27:08 +00:00
glEnable ( GL_MULTISAMPLE ) ;
2016-07-31 11:56:30 +00:00
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 ) ;
}
2018-08-19 19:27:08 +00:00
void CGLView : : resizeGL ( int width , int height ) {
mCamera_Viewport_AspectRatio = ( GLdouble ) width / height ;
glViewport ( 0 , 0 , width , height ) ;
2016-07-31 11:56:30 +00:00
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 ( ) {
2018-05-24 09:31:49 +00:00
// Disable lighting. Colors must be bright and colorful)
if ( mLightingEnabled ) glDisable ( GL_LIGHTING ) ; ///TODO: display list
// For same reason - disable textures.
glBindTexture ( GL_TEXTURE_1D , 0 ) ;
2016-11-08 13:53:52 +00:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glBindTexture ( GL_TEXTURE_3D , 0 ) ;
glEnable ( GL_COLOR_MATERIAL ) ;
glBegin ( GL_LINES ) ;
2018-08-19 19:27:08 +00:00
// X, -X
2018-05-25 18:19:06 +00:00
glColor3f ( 1.0f , 0.0f , 0.0f ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 100000.0 , 0.0 , 0.0 ) ;
glColor3f ( 0.5f , 0.5f , 1.0f ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( - 100000.0 , 0.0 , 0.0 ) ;
// Y, -Y
glColor3f ( 0.0f , 1.0f , 0.0f ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , 100000.0 , 0.0 ) ;
glColor3f ( 1.0f , 0.0f , 1.0f ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , - 100000.0 , 0.0 ) ;
// Z, -Z
glColor3f ( 0.0f , 0.0f , 1.0f ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , 0.0 , 100000.0 ) ;
glColor3f ( 1.0f , 1.0f , 0.0f ) , glVertex3f ( 0.0 , 0.0 , 0.0 ) , glVertex3f ( 0.0 , 0.0 , - 100000.0 ) ;
glColor3f ( 1.0f , 1.0f , 1.0f ) ;
2018-08-19 19:27:08 +00:00
glEnd ( ) ;
// Restore previous state of lighting.
if ( mLightingEnabled ) {
glEnable ( GL_LIGHTING ) ;
}
2016-11-08 13:53:52 +00:00
}
2018-08-19 19:27:08 +00:00
void CGLView : : paintGL ( ) {
2018-05-25 18:19:06 +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 ( ) ;
2018-08-19 19:27:08 +00:00
2016-07-31 11:56:30 +00:00
// Apply current camera transformations.
2018-05-25 18:19:06 +00:00
# if ASSIMP_DOUBLE_PRECISION
glMultMatrixd ( ( GLdouble * ) & mHelper_Camera . Rotation_AroundCamera ) ;
glTranslated ( - mHelper_Camera . Translation_ToScene . x , - mHelper_Camera . Translation_ToScene . y , - mHelper_Camera . Translation_ToScene . z ) ;
glMultMatrixd ( ( GLdouble * ) & mHelper_Camera . Rotation_Scene ) ;
# else
2016-07-31 11:56:30 +00:00
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 ) ;
2018-05-25 18:19:06 +00:00
# endif // ASSIMP_DOUBLE_PRECISION
2016-07-31 11:56:30 +00:00
// Coordinate system
2018-08-19 19:27:08 +00:00
if ( mScene_AxesEnabled ) {
2018-04-05 07:50:30 +00:00
drawCoordSystem ( ) ;
}
2016-07-31 11:56:30 +00:00
glDisable ( GL_COLOR_MATERIAL ) ;
2018-08-19 19:27:08 +00:00
// Scene
if ( mScene ! = nullptr ) {
2016-07-31 11:56:30 +00:00
Draw_Node ( mScene - > mRootNode ) ;
// Scene BBox
2018-08-19 19:27:08 +00:00
if ( mScene_DrawBBox ) {
Draw_BBox ( mScene_BBox ) ;
}
2016-07-31 11:56:30 +00:00
}
2018-08-19 19:27:08 +00:00
emit Paint_Finished ( ( size_t ) time_paintbegin . msecsTo ( QTime : : currentTime ( ) ) , mHelper_Camera . Translation_ToScene . Length ( ) ) ;
2016-07-31 11:56:30 +00:00
}
2018-08-19 19:27:08 +00:00
CGLView : : CGLView ( QWidget * pParent )
: QOpenGLWidget ( pParent )
, mGLContext_Current ( false ) {
// set initial view
mHelper_CameraDefault . SetDefault ( ) ;
Camera_Set ( 0 ) ;
2016-07-31 11:56:30 +00:00
}
2018-08-19 19:27:08 +00:00
CGLView : : ~ CGLView ( ) {
2016-07-31 11:56:30 +00:00
FreeScene ( ) ;
}
2018-08-19 19:27:08 +00:00
void CGLView : : FreeScene ( ) {
2016-07-31 11:56:30 +00:00
// 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 ( ) ;
2019-09-03 06:02:56 +00:00
for ( int idx = 0 ; idx < id_tex_size ; idx + + , + + it )
2016-07-31 11:56:30 +00:00
{
id_tex [ idx ] = it . value ( ) ;
}
glDeleteTextures ( id_tex_size , id_tex ) ;
mTexture_IDMap . clear ( ) ;
delete [ ] id_tex ;
}
}
2018-08-19 19:27:08 +00:00
void CGLView : : SetScene ( const aiScene * pScene , const QString & pScenePath ) {
FreeScene ( ) ; // Clear old data
2016-07-31 11:56:30 +00:00
// Why checking here, not at begin of function. Because old scene may not exist at know. So, need cleanup.
2018-08-19 19:27:08 +00:00
if ( pScene = = nullptr ) {
return ;
}
2016-07-31 11:56:30 +00:00
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 ) ;
//
2018-08-19 19:27:08 +00:00
// Create vertices indices arrays splitted by primitive type.
2016-07-31 11:56:30 +00:00
//
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
2018-08-19 19:27:08 +00:00
// Use index if name is empty.
if ( name . isEmpty ( ) ) {
name + = QString ( " %1 " ) . arg ( idx_light ) ;
}
2016-07-31 11:56:30 +00:00
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
}
2018-08-19 19:27:08 +00:00
void CGLView : : Lighting_Enable ( ) {
2016-07-31 11:56:30 +00:00
mLightingEnabled = true ;
glEnable ( GL_LIGHTING ) ;
}
2018-08-19 19:27:08 +00:00
void CGLView : : Lighting_Disable ( ) {
glDisable ( GL_LIGHTING ) ;
2016-07-31 11:56:30 +00:00
mLightingEnabled = false ;
}
void CGLView : : Lighting_EditSource ( const size_t pLightNumber , const SLightParameters & pLightParameters )
{
2018-08-18 09:07:12 +00:00
const size_t light_num = GL_LIGHT0 + pLightNumber ;
2016-07-31 11:56:30 +00:00
2018-08-18 09:07:12 +00:00
GLfloat farr [ 4 ] ;
2016-07-31 11:56:30 +00:00
if ( pLightNumber > = GL_MAX_LIGHTS ) return ; ///TODO: return value;
2018-05-25 18:19:06 +00:00
// Ambient color
2018-08-18 09:07:12 +00:00
farr [ 0 ] = pLightParameters . Ambient . r ;
farr [ 1 ] = pLightParameters . Ambient . g ;
farr [ 2 ] = pLightParameters . Ambient . b ;
farr [ 3 ] = pLightParameters . Ambient . a ;
2018-05-25 18:19:06 +00:00
glLightfv ( light_num , GL_AMBIENT , farr ) ;
2018-08-18 09:07:12 +00:00
// Diffuse color
farr [ 0 ] = pLightParameters . Diffuse . r ;
farr [ 1 ] = pLightParameters . Diffuse . g ;
farr [ 2 ] = pLightParameters . Diffuse . b ;
farr [ 3 ] = pLightParameters . Diffuse . a ;
2018-05-25 18:19:06 +00:00
glLightfv ( light_num , GL_DIFFUSE , farr ) ;
2018-08-18 09:07:12 +00:00
// Specular color
farr [ 0 ] = pLightParameters . Specular . r ;
farr [ 1 ] = pLightParameters . Specular . g ;
farr [ 2 ] = pLightParameters . Specular . b ;
farr [ 3 ] = pLightParameters . Specular . a ;
2018-05-25 18:19:06 +00:00
glLightfv ( light_num , GL_SPECULAR , farr ) ;
2018-08-18 09:07:12 +00:00
// Other parameters
2016-07-31 11:56:30 +00:00
switch ( pLightParameters . Type )
{
case aiLightSource_DIRECTIONAL :
// Direction
2018-05-25 18:19:06 +00:00
farr [ 0 ] = pLightParameters . For . Directional . Direction . x , farr [ 1 ] = pLightParameters . For . Directional . Direction . y ;
2016-07-31 11:56:30 +00:00
farr [ 2 ] = pLightParameters . For . Directional . Direction . z ; farr [ 3 ] = 0 ;
glLightfv ( light_num , GL_POSITION , farr ) ;
break ;
case aiLightSource_POINT :
// Position
2018-05-25 18:19:06 +00:00
farr [ 0 ] = pLightParameters . For . Point . Position . x , farr [ 1 ] = pLightParameters . For . Point . Position . y ;
2016-07-31 11:56:30 +00:00
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
2018-05-25 18:19:06 +00:00
farr [ 0 ] = pLightParameters . For . Spot . Position . x , farr [ 1 ] = pLightParameters . For . Spot . Position . y , farr [ 2 ] = pLightParameters . For . Spot . Position . z ; farr [ 3 ] = 1 ;
2016-07-31 11:56:30 +00:00
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
2018-05-25 18:19:06 +00:00
farr [ 0 ] = pLightParameters . For . Spot . Direction . x , farr [ 1 ] = pLightParameters . For . Spot . Direction . y , farr [ 2 ] = pLightParameters . For . Spot . Direction . z ; farr [ 3 ] = 0 ;
2016-07-31 11:56:30 +00:00
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
2018-05-25 18:19:06 +00:00
farr [ 0 ] = pLightParameters . For . Point . Position . x , farr [ 1 ] = pLightParameters . For . Point . Position . y ;
2016-07-31 11:56:30 +00:00
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)
}
2018-08-19 19:27:08 +00:00
void CGLView : : Lighting_EnableSource ( const size_t pLightNumber ) {
2016-07-31 11:56:30 +00:00
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 ) ;
}
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 ) ;
}
2018-06-17 18:37:09 +00:00
void CGLView : : Camera_RotateScene ( const GLfloat pAngle_X , const GLfloat pAngle_Y , const GLfloat pAngle_Z , const aiMatrix4x4 * pMatrix_Rotation_Initial ) {
auto deg2rad = [ ] ( const GLfloat pDegree ) - > GLfloat {
2018-08-18 09:07:12 +00:00
return pDegree * AI_MATH_PI / 180.0f ;
2018-06-17 18:37:09 +00:00
} ;
2016-07-31 11:56:30 +00:00
aiMatrix4x4 mat_rot ;
mat_rot . FromEulerAnglesXYZ ( deg2rad ( pAngle_X ) , deg2rad ( pAngle_Y ) , deg2rad ( pAngle_Z ) ) ;
2018-05-24 14:11:21 +00:00
if ( pMatrix_Rotation_Initial ! = nullptr )
mHelper_Camera . Rotation_Scene = * pMatrix_Rotation_Initial * mat_rot ;
else
mHelper_Camera . Rotation_Scene * = mat_rot ;
2016-07-31 11:56:30 +00:00
}
2018-05-24 14:11:21 +00:00
void CGLView : : Camera_Rotate ( const GLfloat pAngle_X , const GLfloat pAngle_Y , const GLfloat pAngle_Z , const aiMatrix4x4 * pMatrix_Rotation_Initial )
2016-07-31 11:56:30 +00:00
{
2018-06-17 18:37:09 +00:00
auto deg2rad = [ ] ( const GLfloat pDegree ) - > GLfloat { return pDegree * AI_MATH_PI / 180.0 ; } ;
2016-07-31 11:56:30 +00:00
aiMatrix4x4 mat_rot ;
mat_rot . FromEulerAnglesXYZ ( deg2rad ( pAngle_X ) , deg2rad ( pAngle_Y ) , deg2rad ( pAngle_Z ) ) ;
2018-05-24 14:11:21 +00:00
if ( pMatrix_Rotation_Initial ! = nullptr )
mHelper_Camera . Rotation_AroundCamera = * pMatrix_Rotation_Initial * mat_rot ;
else
mHelper_Camera . Rotation_AroundCamera * = mat_rot ;
2016-07-31 11:56:30 +00:00
}
void CGLView : : Camera_Translate ( const GLfloat pTranslate_X , const GLfloat pTranslate_Y , const GLfloat pTranslate_Z )
{
2018-06-17 18:37:09 +00:00
aiVector3D vect_tr ( pTranslate_X , pTranslate_Y , pTranslate_Z ) ;
2016-07-31 11:56:30 +00:00
vect_tr * = mHelper_Camera . Rotation_AroundCamera ;
mHelper_Camera . Translation_ToScene + = vect_tr ;
}
2018-05-24 14:11:21 +00:00
void CGLView : : Camera_Matrix ( aiMatrix4x4 & pRotation_Camera , aiMatrix4x4 & pRotation_Scene , aiVector3D & pTranslation_Camera )
{
pRotation_Camera = mHelper_Camera . Rotation_AroundCamera ;
pRotation_Scene = mHelper_Camera . Rotation_Scene ;
pTranslation_Camera = mHelper_Camera . Translation_ToScene ;
}