345 lines
10 KiB
C++
345 lines
10 KiB
C++
/// \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();
|
|
}
|