Merge pull request #960 from smalcom/assimp_qt_viewer

[+] 3D viewer which uses Assimp and Qt4.
pull/964/head
Kim Kulling 2016-08-01 20:15:00 +02:00 committed by GitHub
commit 6003616b07
12 changed files with 2559 additions and 0 deletions

View File

@ -306,6 +306,32 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
ENDIF ( WIN32 )
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
# Check dependencies for assimp_qt_viewer.
# Why here? Maybe user do not want Qt viewer and have no Qt.
# Why assimp_qt_viewer/CMakeLists.txt still contain similar check?
# Because viewer can be build independently of Assimp.
FIND_PACKAGE(Qt4 QUIET)
FIND_PACKAGE(DevIL QUIET)
FIND_PACKAGE(OpenGL QUIET)
IF ( Qt4_FOUND AND IL_FOUND AND OPENGL_FOUND)
ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
ELSE()
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "")
IF (NOT Qt4_FOUND)
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt4")
ENDIF (NOT Qt4_FOUND)
IF (NOT IL_FOUND)
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} DevIL")
ENDIF (NOT IL_FOUND)
IF (NOT OPENGL_FOUND)
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL")
ENDIF (NOT OPENGL_FOUND)
MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}")
ENDIF ( Qt4_FOUND AND IL_FOUND AND OPENGL_FOUND)
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
option ( ASSIMP_BUILD_SAMPLES

View File

@ -0,0 +1,44 @@
project(assimp_qt_viewer)
set(PROJECT_VERSION "")
cmake_minimum_required(VERSION 2.6)
find_package(Qt4 REQUIRED)
find_package(DevIL REQUIRED)
find_package(OpenGL REQUIRED)
include_directories(
${QT_INCLUDES}
${Assimp_SOURCE_DIR}/include
${Assimp_SOURCE_DIR}/code
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}
${OPENGL_INCLUDE_DIR}
${IL_INCLUDE_DIR}
)
link_directories(${Assimp_BINARY_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pedantic -Wall")
set(assimp_qt_viewer_SRCS main.cpp loggerview.cpp glview.cpp mainwindow.cpp)
qt4_wrap_ui(UISrcs mainwindow.ui)
qt4_wrap_cpp(MOCrcs mainwindow.hpp glview.hpp)
add_executable(${PROJECT_NAME} ${assimp_qt_viewer_SRCS} ${UISrcs} ${MOCrcs})
target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${IL_LIBRARIES} ${OPENGL_LIBRARIES} assimp)
if(WIN32) # Check if we are on Windows
if(MSVC) # Check if we are using the Visual Studio compiler
set_target_properties(TestProject PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
elseif(CMAKE_COMPILER_IS_GNUCXX)
# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") # Not tested
else()
message(SEND_ERROR "You are using an unsupported Windows compiler! (Not MSVC or GCC)")
endif()
elseif(UNIX)
# Nothing special required
else()
message(SEND_ERROR "You are on an unsupported platform! (Not Win32 or Unix)")
endif()
set_property(TARGET ${PROJECT_NAME} PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,382 @@
/// \file glview.hpp
/// \brief OpenGL visualisation.
/// \author smal.root@gmail.com
/// \date 2016
#pragma once
// Header files, Qt.
#include <QtOpenGL>
// Header files Assimp
#include <assimp/scene.h>
/// \class CGLView
/// Class which hold and render scene.
class CGLView : public QGLWidget
{
Q_OBJECT
/**********************************/
/************* Types **************/
/**********************************/
private:
/// \struct SBBox
/// Bounding box for object.
struct SBBox
{
aiVector3D Minimum;///< Minimum values of coordinates.
aiVector3D Maximum;///< Maximum values of coordinates.
};
/// \struct SHelper_Mesh
/// Helper object for fast rendering of mesh (\ref aiMesh).
struct SHelper_Mesh
{
const size_t Quantity_Point;///< Quantity of points.
const size_t Quantity_Line;///< Quantity of lines.
const size_t Quantity_Triangle;///< Quantity of triangles.
GLuint* Index_Point;///< Array of indices for drawing points.
GLuint* Index_Line;///< Array of indices for drawing lines.
GLuint* Index_Triangle;///< Array of indices for drawing triangles.
const SBBox BBox;///< BBox of mesh.
/// \fn explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}})
/// Constructor.
/// \param [in] pQuantity_Point - quantity of points.
/// \param [in] pQuantity_Line - quantity of lines.
/// \param [in] pQuantity_Triangle - quantity of triangles.
/// \param [in] pBBox - BBox of mesh.
explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}});
/// \fn ~SHelper_Mesh()
/// Destructor.
~SHelper_Mesh();
};
/// \struct SHelper_Camera
/// Information about position of the camera in space.
struct SHelper_Camera
{
aiVector3D Position;///< Coordinates of the camera.
aiVector3D Target;///< Target point of the camera.
// Transformation path:
// set Camera -> Rotation_AroundCamera -> Translation_ToScene -> Rotation_Scene -> draw Scene
aiMatrix4x4 Rotation_AroundCamera;///< Rotation matrix which set rotation angles of the scene around camera.
aiMatrix4x4 Rotation_Scene;///< Rotation matrix which set rotation angles of the scene around own center.
aiVector3D Translation_ToScene;///< Translation vector from camera to the scene.
/// \fn void SetDefault()
/// Set default parameters of camera.
void SetDefault();
};
public:
/// \enum ELightType
/// Type of light source.
enum class ELightType { Directional, Point, Spot };
/// \struct SLightParameters
/// Parameters of light source.
struct SLightParameters
{
aiLightSourceType Type;///< Type of light source.
aiColor4D Ambient;///< Ambient RGBA intensity of the light.
aiColor4D Diffuse;///< Diffuse RGBA intensity of the light.
aiColor4D Specular;///< Specular RGBA intensity of the light.
union UFor
{
/// \struct SDirectional
/// Parameters of directional light source.
struct SDirectional
{
aiVector3D Direction;
SDirectional() {}
} Directional;
/// \struct SPoint
/// Parameters of point light source.
struct SPoint
{
aiVector3D Position;
GLfloat Attenuation_Constant;
GLfloat Attenuation_Linear;
GLfloat Attenuation_Quadratic;
SPoint() {}
} Point;
/// \struct SSpot
/// Parameters of spot light source.
struct SSpot
{
aiVector3D Position;
GLfloat Attenuation_Constant;
GLfloat Attenuation_Linear;
GLfloat Attenuation_Quadratic;
aiVector3D Direction;
GLfloat CutOff;
SSpot() {}
} Spot;
UFor() {}
} For;
SLightParameters() {}
};
/**********************************/
/************ Variables ***********/
/**********************************/
private:
// Scene
const aiScene* mScene = nullptr;///< Copy of pointer to scene (\ref aiScene).
SBBox mScene_BBox;///< Bounding box of scene.
aiVector3D mScene_Center;///< Coordinates of center of the scene.
bool mScene_DrawBBox = false;///< Flag which control drawing scene BBox.
// Meshes
size_t mHelper_Mesh_Quantity = 0;///< Quantity of meshes in scene.
SHelper_Mesh** mHelper_Mesh = nullptr;///< Array of pointers to helper objects for drawing mesh. Sequence of meshes are equivalent to \ref aiScene::mMeshes.
// Cameras
SHelper_Camera mHelper_Camera;///< Information about current camera placing in space.
SHelper_Camera mHelper_CameraDefault;///< Information about default camera initial placing in space.
bool mCamera_DefaultAdded = true;///< If true then scene has no defined cameras and default was added, if false - scene has defined cameras.
GLdouble mCamera_FOVY = 45.0;///< Specifies the field of view angle, in degrees, in the y direction.
GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
// Lighting
bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled.
// Textures
QMap<QString, GLuint> mTexture_IDMap;///< Map image filenames to textures ID's.
/**********************************/
/************ Functions ***********/
/**********************************/
private:
// Why in some cases pointers are used? Because: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566
template<typename TArg> void AssignIfLesser(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue < *pBaseValue) *pBaseValue = pTestValue; }
template<typename TArg> void AssignIfGreater(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue > *pBaseValue) *pBaseValue = pTestValue; }
template<typename TArg> void AssignIfLesser(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue < pBaseValue) pBaseValue = pTestValue; }
template<typename TArg> void AssignIfGreater(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue > pBaseValue) pBaseValue = pTestValue; }
/// \fn void Material_Apply(const aiMaterial* pMaterial)
/// Enable pointed material.
/// \param [in] pMaterial - pointer to material which must be used.
void Material_Apply(const aiMaterial* pMaterial);
/// \fn void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix)
/// Calculate matrix for transforming coordinates from pointed node to root node (read as "global coordinate system").
/// \param [in] pNode - pointer initial node from which relative coordintaes will be taken,
/// \param [out] pOutMatrix - matrix for transform relative coordinates in \ref pNode to coordinates in root node (\ref aiScene::mRootNode).
void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix);
/// \fn void ImportTextures()
/// Import textures.
/// \param [in] pScenePath - path to the file of the scene.
void ImportTextures(const QString& pScenePath);
/// \fn void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParentNode_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign)
/// Calculate BBox for pointed node. Function walk thru child nodes and apply all transformations.
/// \param [in] pNode - reference to node for which needed BBox.
/// \param [in] pParent_TransformationMatrix - reference to parent (parent for pNode) transformation matrix.
/// \param [in,out] pNodeBBox - reference to where pNode BBox will be placed. It will expanded by child nodes BBoxes.
/// \param [in] pFirstAssign - means that pNodeBBox not contain valid BBox at now and assign ('=') will used for setting new value, If
/// false then \ref BBox_Extend will be used for setting new BBox.
void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign);
/// \fn void BBox_Extend(const SBBox& pChild, SBBox& pParent)
/// Check and if need - extend current node BBox with BBox of child node.
/// \param [in] pChild - reference to BBox which used for extend parent BBox.
/// \param [in.out] pParent - BBox which will be extended using child BBox.
void BBox_Extend(const SBBox& pChild, SBBox& pParent);
/// \fn void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8])
/// Get vertices of a parallelepiped which is described by BBox.
/// \param [in] pBBox - input BBox.
/// \param [out] pVertices - array of vertices.
void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8]);
/// \fn void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox)
/// Calculate BBox for vertices array.
/// \param [in] pVertices - vertices array.
/// \param [in] pVerticesQuantity - quantity of vertices in array. If 0 then pBBox will be assigned with {{0, 0, 0}, {0, 0, 0}}.
/// \param [out] pBBox - calculated BBox.
void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox);
/********************************************************************/
/************************ Logging functions *************************/
/********************************************************************/
/// \fn void LogInfo(const QString& pMessage)
/// Add message with severity "Warning" to log.
void LogInfo(const QString& pMessage);
/// \fn void LogError(const QString& pMessage)
/// Add message with severity "Error" to log.
void LogError(const QString& pMessage);
/********************************************************************/
/************************** Draw functions **************************/
/********************************************************************/
/// \fn void Draw_Node(const aiNode* pNode)
/// Apply node transformation and draw meshes assigned to this node.
/// \param [in] pNode - pointer to node for drawing (\ref aiNode).
void Draw_Node(const aiNode* pNode);
/// \fn void Draw_Mesh(const size_t pMesh_Index)
/// Draw mesh.
/// \param [in] pMesh_Index - index of mesh which must be drawn. Index point to mesh in \ref mHelper_Mesh.
void Draw_Mesh(const size_t pMesh_Index);
/// \fn void Draw_BBox(const SBBox& pBBox)
/// Draw bounding box using lines.
/// \param [in] pBBox - bounding box for drawing.
void Draw_BBox(const SBBox& pBBox);
/********************************************************************/
/*********************** Overrided functions ************************/
/********************************************************************/
protected:
/// \fn void initializeGL() override
/// Overrided function for initialise OpenGL.
void initializeGL() override;
/// \fn void resizeGL(int pWidth, int pHeight) override
/// \param [in] pWidth - new width of viewport.
/// \param [in] pHeight - new height of viewport.
void resizeGL(int pWidth, int pHeight) override;
/// \fn void paintGL() override
/// Overrided function for rendering.
void paintGL() override;
public:
/********************************************************************/
/********************** Constructor/Destructor **********************/
/********************************************************************/
/// \fn explicit CGLView(QWidget* pParent)
/// Constructor.
/// \param [in] pParent - parent widget.
explicit CGLView(QWidget* pParent);
/// \fn virtual ~CGLView()
/// Destructor.
virtual ~CGLView();
/********************************************************************/
/********************* Scene control functions **********************/
/********************************************************************/
/// \fn void FreeScene()
/// Free all helper objects data.
void FreeScene();
/// \fn void SetScene(const aiScene* pScene)
/// Set scene for rendering.
/// \param [in] pScene - pointer to scene.
/// \param [in] pScenePath - path to the file of the scene.
void SetScene(const aiScene* pScene, const QString& pScenePath);
/// \fn void Enable_SceneBBox(const bool pEnable)
/// Enable drawing scene bounding box.
/// \param [in] pEnable - if true then bbox will be drawing, if false - will not be drawing.
void Enable_SceneBBox(const bool pEnable) { mScene_DrawBBox = pEnable; }
/// \fn void Enable_Textures(const bool pEnable)
/// Control textures drawing.
/// \param [in] pEnable - if true then enable textures, false - disable textures.
void Enable_Textures(const bool pEnable);
/********************************************************************/
/******************** Lighting control functions ********************/
/********************************************************************/
/// \fn void Lighting_Enable()
/// Enable OpenGL lighting.
void Lighting_Enable();
/// \fn void Lighting_Disable()
/// Disable OpenGL lighting.
void Lighting_Disable();
/// \fn void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters)
/// Edit light source properties.
/// \param [in] pLightNumber - light source number. \ref aiScene::mLights.
/// \param [in] pLightParameters - light source parameters.
void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters);///TODO: function set
/// \fn void Lighting_EnableSource(const size_t pLightNumber)
/// Enable light source.
/// \param [in] pLightNumber - light source number. \ref aiScene::mLights.
void Lighting_EnableSource(const size_t pLightNumber);
///void Lighting_DisableSource(const size_t pLightNumber)
/// Disable light source,
/// \param [in] pLightNumber - light source number. \ref aiScene::mLights.
void Lighting_DisableSource(const size_t pLightNumber);
/********************************************************************/
/******************** Cameras control functions *********************/
/********************************************************************/
/// \fn void Camera_Set(const size_t pCameraNumber)
/// Set view from pointed camera.
/// \param [in] pCamera_Index - index of the camera (\ref aiScene::mCameras).
void Camera_Set(const size_t pCameraNumber);
/// \fn void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z)
/// Rotate scene around axisees.
/// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees.
/// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees.
/// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees.
void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z);
/// \fn void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z)
/// Rotate camera around axisees.
/// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees.
/// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees.
/// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees.
void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z);
/// \fn void Camera_Translate(const size_t pTranslate_X, const size_t pTranslate_Y, const size_t pTranslate_Z)
/// Translate camera along axises. In local coordinates.
/// \param [in] pTranslate_X - specifies the X coordinate of translation vector.
/// \param [in] pTranslate_Y - specifies the Y coordinate of translation vector.
/// \param [in] pTranslate_Z - specifies the Z coordinate of translation vector.
void Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z);
signals:
/// \fn void Paint_Finished(const size_t pPaintTime, const GLfloat pDistance)
///< Signal. Emits when execution of \ref paintGL is end.
/// \param [out] pPaintTime_ms - time spent for rendering, in milliseconds.
/// \param [out] pDistance - distance between current camera and center of the scene. \sa SHelper_Camera::Translation_ToScene.
void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance);
/// \fn void SceneObject_Camera(const QString& pName)
/// Signal. Emit for every camera found in scene. Also for default camera.
/// \param [out] pName - name of the camera.
void SceneObject_Camera(const QString& pName);
/// \fn void SceneObject_LightSource(const QString& pName)
/// Signal. Emit for every light source found in scene. Also for default light source.
/// \param [out] pName - name of the light source.
void SceneObject_LightSource(const QString& pName);
};// class CGLView

View File

@ -0,0 +1,19 @@
/// \file loggerview.cpp
/// \brief Stream for Assimp logging subsystem.
/// \author smal.root@gmail.com
/// \date 2016
#include "loggerview.hpp"
// Header files, Qt.
#include <QTime>
CLoggerView::CLoggerView(QTextBrowser* pOutputWidget)
: mOutputWidget(pOutputWidget)
{
}
void CLoggerView::write(const char *pMessage)
{
mOutputWidget->insertPlainText(QString("[%1] %2").arg(QTime::currentTime().toString()).arg(pMessage));
}

View File

@ -0,0 +1,33 @@
/// \file loggerview.hpp
/// \brief Stream for Assimp logging subsystem.
/// \author smal.root@gmail.com
/// \date 2016
#pragma once
// Header files, Qt.
#include <QTextBrowser>
// Header files, Assimp.
#include <assimp/DefaultLogger.hpp>
/// \class CLoggerView
/// GUI-stream for Assimp logging subsytem. Get data for logging and write it to output widget.
class CLoggerView final : public Assimp::LogStream
{
private:
QTextBrowser* mOutputWidget;///< Widget for displaying messages.
public:
/// \fn explicit CLoggerView(QTextBrowser* pOutputWidget)
/// Constructor.
/// \param [in] pOutputWidget - pointer to output widget.
explicit CLoggerView(QTextBrowser* pOutputWidget);
/// \fn virtual void write(const char *pMessage)
/// Write message to output widget. Used by Assimp.
/// \param [in] pMessage - message for displaying.
virtual void write(const char *pMessage);
};

View File

@ -0,0 +1,21 @@
/// \file main.cpp
/// \brief Start-up file which contain function "main".
/// \author smal.root@gmail.com
/// \date 2016
// Thanks to acorn89 for support.
// Header files, project.
#include "mainwindow.hpp"
// Header files, Qt.
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

View File

@ -0,0 +1,344 @@
/// \file mainwindow.hpp
/// \brief Main window and algorhytms.
/// \author smal.root@gmail.com
/// \date 2016
#include "mainwindow.hpp"
#include "ui_mainwindow.h"
// Header files, Assimp.
#include <assimp/Exporter.hpp>
#include <assimp/postprocess.h>
#ifndef __unused
#define __unused __attribute__((unused))
#endif // __unused
/**********************************/
/************ Functions ***********/
/**********************************/
/********************************************************************/
/********************* Import/Export functions **********************/
/********************************************************************/
void MainWindow::ImportFile(const QString &pFileName)
{
using namespace Assimp;
QTime time_begin = QTime::currentTime();
if(mScene != nullptr)
{
mImporter.FreeScene();
mGLView->FreeScene();
}
// Try to import scene.
mScene = mImporter.ReadFile(pFileName.toStdString(), aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_ValidateDataStructure | \
aiProcess_GenUVCoords | aiProcess_TransformUVCoords | aiProcess_FlipUVs);
if(mScene != nullptr)
{
ui->lblLoadTime->setText(QString("%1").arg(time_begin.secsTo(QTime::currentTime())));
LogInfo("Import done: " + pFileName);
// Prepare widgets for new scene.
ui->leFileName->setText(pFileName.right(pFileName.length() - pFileName.lastIndexOf('/') - 1));
ui->lstLight->clear();
ui->lstCamera->clear();
ui->cbxLighting->setChecked(true), mGLView->Lighting_Enable();
ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false);
ui->cbxTextures->setChecked(true), mGLView->Enable_Textures(true);
//
// Fill info labels
//
// Cameras
ui->lblCameraCount->setText(QString("%1").arg(mScene->mNumCameras));
// Lights
ui->lblLightCount->setText(QString("%1").arg(mScene->mNumLights));
// Meshes, faces, vertices.
size_t qty_face = 0;
size_t qty_vert = 0;
for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++)
{
qty_face += mScene->mMeshes[idx_mesh]->mNumFaces;
qty_vert += mScene->mMeshes[idx_mesh]->mNumVertices;
}
ui->lblMeshCount->setText(QString("%1").arg(mScene->mNumMeshes));
ui->lblFaceCount->setText(QString("%1").arg(qty_face));
ui->lblVertexCount->setText(QString("%1").arg(qty_vert));
// Animation
if(mScene->mNumAnimations)
ui->lblHasAnimation->setText("yes");
else
ui->lblHasAnimation->setText("no");
//
// Set scene for GL viewer.
//
mGLView->SetScene(mScene, pFileName);
// Select first camera
ui->lstCamera->setCurrentRow(0);
mGLView->Camera_Set(0);
// Scene is loaded, do first rendering.
LogInfo("Scene is ready for rendering.");
mGLView->updateGL();
}
else
{
ui->lblLoadTime->clear();
LogError(QString("Error parsing \'%1\' : \'%2\'").arg(pFileName).arg(mImporter.GetErrorString()));
}// if(mScene != nullptr)
}
/********************************************************************/
/************************ Logging functions *************************/
/********************************************************************/
void MainWindow::LogInfo(const QString& pMessage)
{
Assimp::DefaultLogger::get()->info(pMessage.toStdString());
}
void MainWindow::LogError(const QString& pMessage)
{
Assimp::DefaultLogger::get()->error(pMessage.toStdString());
}
/********************************************************************/
/*********************** Overrided functions ************************/
/********************************************************************/
void MainWindow::mousePressEvent(QMouseEvent* pEvent)
{
if(pEvent->button() & Qt::LeftButton)
mPosition_Pressed_LMB = pEvent->pos();
else if(pEvent->button() & Qt::RightButton)
mPosition_Pressed_RMB = pEvent->pos();
}
void MainWindow::mouseMoveEvent(QMouseEvent* pEvent)
{
if(pEvent->buttons() & Qt::LeftButton)
{
GLfloat dx = 180 * GLfloat(pEvent->x() - mPosition_Pressed_LMB.x()) / mGLView->width();
GLfloat dy = 180 * GLfloat(pEvent->y() - mPosition_Pressed_LMB.y()) / mGLView->height();
if(pEvent->modifiers() & Qt::ShiftModifier)
mGLView->Camera_RotateScene(dy, 0, dx);// Rotate around oX and oZ axises.
else
mGLView->Camera_RotateScene(dy, dx, 0);// Rotate around oX and oY axises.
mGLView->updateGL();
mPosition_Pressed_LMB = pEvent->pos();
}
if(pEvent->buttons() & Qt::RightButton)
{
GLfloat dx = 180 * GLfloat(pEvent->x() - mPosition_Pressed_RMB.x()) / mGLView->width();
GLfloat dy = 180 * GLfloat(pEvent->y() - mPosition_Pressed_RMB.y()) / mGLView->height();
if(pEvent->modifiers() & Qt::ShiftModifier)
mGLView->Camera_Rotate(dy, 0, dx);// Rotate around oX and oZ axises.
else
mGLView->Camera_Rotate(dy, dx, 0);// Rotate around oX and oY axises.
mGLView->updateGL();
mPosition_Pressed_RMB = pEvent->pos();
}
}
void MainWindow::keyPressEvent(QKeyEvent* pEvent)
{
GLfloat step;
if(pEvent->modifiers() & Qt::ControlModifier)
step = 10;
else if(pEvent->modifiers() & Qt::AltModifier)
step = 100;
else
step = 1;
if(pEvent->key() == Qt::Key_A)
mGLView->Camera_Translate(-step, 0, 0);
else if(pEvent->key() == Qt::Key_D)
mGLView->Camera_Translate(step, 0, 0);
else if(pEvent->key() == Qt::Key_W)
mGLView->Camera_Translate(0, step, 0);
else if(pEvent->key() == Qt::Key_S)
mGLView->Camera_Translate(0, -step, 0);
else if(pEvent->key() == Qt::Key_Up)
mGLView->Camera_Translate(0, 0, -step);
else if(pEvent->key() == Qt::Key_Down)
mGLView->Camera_Translate(0, 0, step);
mGLView->updateGL();
}
/********************************************************************/
/********************** Constructor/Destructor **********************/
/********************************************************************/
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow),
mScene(nullptr)
{
using namespace Assimp;
ui->setupUi(this);
// Create OpenGL widget
mGLView = new CGLView(this);
mGLView->setMinimumSize(800, 600);
mGLView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
mGLView->setFocusPolicy(Qt::StrongFocus);
// Connect to GLView signals.
connect(mGLView, SIGNAL(Paint_Finished(size_t, GLfloat)), SLOT(Paint_Finished(size_t, GLfloat)));
connect(mGLView, SIGNAL(SceneObject_Camera(QString)), SLOT(SceneObject_Camera(QString)));
connect(mGLView, SIGNAL(SceneObject_LightSource(QString)), SLOT(SceneObject_LightSource(QString)));
// and add it to layout
ui->hlMainView->insertWidget(0, mGLView, 4);
// Create logger
mLoggerView = new CLoggerView(ui->tbLog);
DefaultLogger::create("", Logger::VERBOSE);
DefaultLogger::get()->attachStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn);
}
MainWindow::~MainWindow()
{
using namespace Assimp;
DefaultLogger::get()->detatchStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn);
DefaultLogger::kill();
if(mScene != nullptr) mImporter.FreeScene();
if(mLoggerView != nullptr) delete mLoggerView;
if(mGLView != nullptr) delete mGLView;
delete ui;
}
/********************************************************************/
/****************************** Slots *******************************/
/********************************************************************/
void MainWindow::Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance)
{
ui->lblRenderTime->setText(QString("%1").arg(pPaintTime_ms));
ui->lblDistance->setText(QString("%1").arg(pDistance));
}
void MainWindow::SceneObject_Camera(const QString& pName)
{
ui->lstCamera->addItem(pName);
}
void MainWindow::SceneObject_LightSource(const QString& pName)
{
ui->lstLight->addItem(pName);
// After item added "currentRow" is still contain old value (even '-1' if first item added). Because "currentRow"/"currentItem" is changed by user interaction,
// not by "addItem". So, "currentRow" must be set manually.
ui->lstLight->setCurrentRow(ui->lstLight->count() - 1);
// And after "selectAll" handler of "signal itemSelectionChanged" will get right "currentItem" and "currentRow" values.
ui->lstLight->selectAll();
}
void MainWindow::on_butOpenFile_clicked()
{
aiString filter_temp;
QString filename, filter;
mImporter.GetExtensionList(filter_temp);
filter = filter_temp.C_Str();
filter.replace(';', ' ');
filter.append(" ;; All (*.*)");
filename = QFileDialog::getOpenFileName(this, "Choose the file", "", filter);
if(!filename.isEmpty()) ImportFile(filename);
}
void MainWindow::on_butExport_clicked()
{
using namespace Assimp;
QString filename, filter, format_id;
Exporter exporter;
QTime time_begin;
aiReturn rv;
if(mScene == nullptr)
{
QMessageBox::critical(this, "Export error", "Scene is empty");
return;
}
// build filter
{
aiString filter_temp;
mImporter.GetExtensionList(filter_temp);
filter = filter_temp.C_Str();
filter.replace(';', ' ');
}
// get file path
filename = QFileDialog::getSaveFileName(this, "Set file name", "", filter);
// extract format ID
format_id = filename.right(filename.length() - filename.lastIndexOf('.') - 1);
if(format_id.isEmpty())
{
QMessageBox::critical(this, "Export error", "File name must has extension.");
return;
}
// begin export
time_begin = QTime::currentTime();
rv = exporter.Export(mScene, format_id.toLocal8Bit(), filename.toLocal8Bit());
ui->lblExportTime->setText(QString("%1").arg(time_begin.secsTo(QTime::currentTime())));
if(rv == aiReturn_SUCCESS)
LogInfo("Export done: " + filename);
else
LogError("Export failed: " + filename);
}
void MainWindow::on_cbxLighting_clicked(bool pChecked)
{
if(pChecked)
mGLView->Lighting_Enable();
else
mGLView->Lighting_Disable();
mGLView->updateGL();
}
void MainWindow::on_lstLight_itemSelectionChanged()
{
bool selected = ui->lstLight->isItemSelected(ui->lstLight->currentItem());
if(selected)
mGLView->Lighting_EnableSource(ui->lstLight->currentRow());
else
mGLView->Lighting_DisableSource(ui->lstLight->currentRow());
mGLView->updateGL();
}
void MainWindow::on_lstCamera_clicked(__unused const QModelIndex &index)
{
mGLView->Camera_Set(ui->lstLight->currentRow());
mGLView->updateGL();
}
void MainWindow::on_cbxBBox_clicked(bool checked)
{
mGLView->Enable_SceneBBox(checked);
mGLView->updateGL();
}
void MainWindow::on_cbxTextures_clicked(bool checked)
{
mGLView->Enable_Textures(checked);
mGLView->updateGL();
}

View File

@ -0,0 +1,131 @@
/// \file mainwindow.hpp
/// \brief Main window and algorhytms.
/// \author smal.root@gmail.com
/// \date 2016
#pragma once
// Header files, Qt.
#include <QMainWindow>
// Header files, project.
#include "glview.hpp"
#include "loggerview.hpp"
// Header files, Assimp.
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
namespace Ui { class MainWindow; }
/// \class MainWindow
/// Main window and algorhytms.
class MainWindow : public QMainWindow
{
Q_OBJECT
/**********************************/
/************ Variables ***********/
/**********************************/
private:
Ui::MainWindow *ui;
CGLView* mGLView;///< Pointer to OpenGL render.
CLoggerView* mLoggerView;///< Pointer to logging object.
Assimp::Importer mImporter;///< Assimp importer.
const aiScene* mScene;///< Pointer to loaded scene (\ref aiScene).
QPoint mPosition_Pressed_LMB;///< Position where was pressed left mouse button.
QPoint mPosition_Pressed_RMB;///< Position where was pressed right mouse button.
/**********************************/
/************ Functions ***********/
/**********************************/
/********************************************************************/
/********************* Import/Export functions **********************/
/********************************************************************/
/// \fn void ImportFile(const QString& pFileName)
/// Import scene from file.
/// \param [in] pFileName - path and name of the file.
void ImportFile(const QString& pFileName);
/********************************************************************/
/************************ Logging functions *************************/
/********************************************************************/
/// \fn void LogInfo(const QString& pMessage)
/// Add message with severity "Warning" to log.
void LogInfo(const QString& pMessage);
/// \fn void LogError(const QString& pMessage)
/// Add message with severity "Error" to log.
void LogError(const QString& pMessage);
/********************************************************************/
/*********************** Overrided functions ************************/
/********************************************************************/
protected:
/// \fn void mousePressEvent(QMouseEvent* pEvent) override
/// Overrided function which handle mouse event "button pressed".
/// \param [in] pEvent - pointer to event data.
void mousePressEvent(QMouseEvent* pEvent) override;
/// \fn void mouseMoveEvent(QMouseEvent* pEvent) override
/// Overrided function which handle mouse event "move".
/// \param [in] pEvent - pointer to event data.
void mouseMoveEvent(QMouseEvent* pEvent) override;
/// \fn void keyPressEvent(QKeyEvent* pEvent) override
/// Overrided function which handle key event "key pressed".
/// \param [in] pEvent - pointer to event data.
void keyPressEvent(QKeyEvent* pEvent) override;
public:
/********************************************************************/
/********************** Constructor/Destructor **********************/
/********************************************************************/
/// \fn explicit MainWindow(QWidget* pParent = 0)
/// \param [in] pParent - pointer to parent widget.
explicit MainWindow(QWidget* pParent = 0);
/// \fn ~MainWindow()
/// Destructor.
~MainWindow();
/********************************************************************/
/****************************** Slots *******************************/
/********************************************************************/
private slots:
/// \fn void Paint_Finished(const int pPaintTime)
/// Show paint/render time and distance between camera and center of the scene.
/// \param [in] pPaintTime_ms - paint time in milliseconds.
void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance);
/// \fn void SceneObject_Camera(const QString& pName)
/// Add camera name to list.
/// \param [in] pName - name of the camera.
void SceneObject_Camera(const QString& pName);
/// \fn void SceneObject_LightSource(const QString& pName)
/// Add lighting source name to list.
/// \param [in] pName - name of the light source,
void SceneObject_LightSource(const QString& pName);
void on_butOpenFile_clicked();
void on_butExport_clicked();
void on_cbxLighting_clicked(bool pChecked);
void on_lstLight_itemSelectionChanged();
void on_lstCamera_clicked(const QModelIndex &index);
void on_cbxBBox_clicked(bool checked);
void on_cbxTextures_clicked(bool checked);
};

View File

@ -0,0 +1,516 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>641</width>
<height>734</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="5,1">
<item>
<layout class="QHBoxLayout" name="hlMainView" stretch="0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="grpFile">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="title">
<string>File</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0" colspan="2">
<widget class="QPushButton" name="butOpenFile">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Open file</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblFileName_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>File name</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leFileName">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblLoadTime_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Load time, s</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblLoadTime">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="Line" name="line">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="butExport">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblExportTime_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Export time, s</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="lblExportTime">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="grpInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="title">
<string>Info</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="lblRenderTime_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Render time, ms</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblRenderTime">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblMeshCount_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Meshes</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblFaceCount_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Faces</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblMeshCount">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblFaceCount">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblVertexCount_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Vertices</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="lblVertexCount">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblLightCount_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Lights</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblCameraCount_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Cameras</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lblHasAnimation_Label">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Animation</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblShaderCount_Label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Shaders</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="lblLightCount">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="lblCameraCount">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="lblShaderCount">
<property name="enabled">
<bool>false</bool>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="lblHasAnimation">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="lblDistance_Label">
<property name="text">
<string>Distance</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="lblDistance">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="grpDynamics">
<property name="enabled">
<bool>false</bool>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="title">
<string>Dynamics</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="butAnimationStart">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Animation start</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="butAnimationStop">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Animation stop</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabInfoAndControl">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Log</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTextBrowser" name="tbLog">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Lights and cameras</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="lstLight">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Light sources of the scene</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::SelectedClicked</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="lstCamera">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Cameras of the scene</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Control</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="cbxLighting">
<property name="toolTip">
<string>Enable/Disable OpenGL lighting</string>
</property>
<property name="text">
<string>Lighting</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="cbxBBox">
<property name="text">
<string>Scene BBox</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="cbxTextures">
<property name="text">
<string>Textures</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>