467 lines
14 KiB
C++
467 lines
14 KiB
C++
/*
|
|
---------------------------------------------------------------------------
|
|
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.
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
#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
|
|
|
|
using namespace Assimp;
|
|
|
|
|
|
void MainWindow::ImportFile(const QString &pFileName) {
|
|
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::number(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::number(mScene->mNumCameras));
|
|
// Lights
|
|
ui->lblLightCount->setText(QString::number(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::number(mScene->mNumMeshes));
|
|
ui->lblFaceCount->setText(QString::number(qty_face));
|
|
ui->lblVertexCount->setText(QString::number(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.");
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
else
|
|
{
|
|
ResetSceneInfos();
|
|
|
|
QString errorMessage = QString("Error parsing \'%1\' : \'%2\'").arg(pFileName).arg(mImporter.GetErrorString());
|
|
QMessageBox::critical(this, "Import error", errorMessage);
|
|
LogError(errorMessage);
|
|
}// if(mScene != nullptr)
|
|
}
|
|
|
|
void MainWindow::ResetSceneInfos()
|
|
{
|
|
ui->lblLoadTime->clear();
|
|
ui->leFileName->clear();
|
|
ui->lblMeshCount->setText("0");
|
|
ui->lblFaceCount->setText("0");
|
|
ui->lblVertexCount->setText("0");
|
|
ui->lblCameraCount->setText("0");
|
|
ui->lblLightCount->setText("0");
|
|
ui->lblHasAnimation->setText("no");
|
|
}
|
|
|
|
/********************************************************************/
|
|
/************************ 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());
|
|
}
|
|
|
|
/********************************************************************/
|
|
/*********************** Override functions ************************/
|
|
/********************************************************************/
|
|
|
|
void MainWindow::mousePressEvent(QMouseEvent* pEvent)
|
|
{
|
|
const QPoint ms_pt = pEvent->pos();
|
|
aiVector3D temp_v3;
|
|
|
|
// Check if GLView is pointed.
|
|
if(childAt(ms_pt) == mGLView)
|
|
{
|
|
if(!mMouse_Transformation.Position_Pressed_Valid)
|
|
{
|
|
mMouse_Transformation.Position_Pressed_Valid = true;// set flag
|
|
// Store current transformation matrices.
|
|
mGLView->Camera_Matrix(mMouse_Transformation.Rotation_AroundCamera, mMouse_Transformation.Rotation_Scene, temp_v3);
|
|
}
|
|
|
|
if(pEvent->button() & Qt::LeftButton)
|
|
mMouse_Transformation.Position_Pressed_LMB = ms_pt;
|
|
else if(pEvent->button() & Qt::RightButton)
|
|
mMouse_Transformation.Position_Pressed_RMB = ms_pt;
|
|
}
|
|
else
|
|
{
|
|
mMouse_Transformation.Position_Pressed_Valid = false;
|
|
}
|
|
}
|
|
|
|
void MainWindow::mouseReleaseEvent(QMouseEvent *pEvent)
|
|
{
|
|
if(pEvent->buttons() == 0) mMouse_Transformation.Position_Pressed_Valid = false;
|
|
|
|
}
|
|
|
|
void MainWindow::mouseMoveEvent(QMouseEvent* pEvent)
|
|
{
|
|
if(mMouse_Transformation.Position_Pressed_Valid)
|
|
{
|
|
if(pEvent->buttons() & Qt::LeftButton)
|
|
{
|
|
GLfloat dx = 180 * GLfloat(pEvent->x() - mMouse_Transformation.Position_Pressed_LMB.x()) / mGLView->width();
|
|
GLfloat dy = 180 * GLfloat(pEvent->y() - mMouse_Transformation.Position_Pressed_LMB.y()) / mGLView->height();
|
|
|
|
if(pEvent->modifiers() & Qt::ShiftModifier)
|
|
mGLView->Camera_RotateScene(dy, 0, dx, &mMouse_Transformation.Rotation_Scene);// Rotate around oX and oZ axises.
|
|
else
|
|
mGLView->Camera_RotateScene(dy, dx, 0, &mMouse_Transformation.Rotation_Scene);// Rotate around oX and oY axises.
|
|
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
|
|
if(pEvent->buttons() & Qt::RightButton)
|
|
{
|
|
GLfloat dx = 180 * GLfloat(pEvent->x() - mMouse_Transformation.Position_Pressed_RMB.x()) / mGLView->width();
|
|
GLfloat dy = 180 * GLfloat(pEvent->y() - mMouse_Transformation.Position_Pressed_RMB.y()) / mGLView->height();
|
|
|
|
if(pEvent->modifiers() & Qt::ShiftModifier)
|
|
mGLView->Camera_Rotate(dy, 0, dx, &mMouse_Transformation.Rotation_AroundCamera);// Rotate around oX and oZ axises.
|
|
else
|
|
mGLView->Camera_Rotate(dy, dx, 0, &mMouse_Transformation.Rotation_AroundCamera);// Rotate around oX and oY axises.
|
|
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
|
|
/********************************************************************/
|
|
/********************** Constructor/Destructor **********************/
|
|
/********************************************************************/
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
: QMainWindow(parent), ui(new Ui::MainWindow),
|
|
mScene(nullptr)
|
|
{
|
|
|
|
// other variables
|
|
mMouse_Transformation.Position_Pressed_Valid = false;
|
|
|
|
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);
|
|
|
|
ResetSceneInfos();
|
|
}
|
|
|
|
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::number(pPaintTime_ms));
|
|
ui->lblDistance->setText(QString::number(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;
|
|
mImporter.GetExtensionList( filter_temp );
|
|
|
|
QString filename, filter;
|
|
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;
|
|
|
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
|
QString filename, filter, format_id;
|
|
Exporter exporter;
|
|
QTime time_begin;
|
|
aiReturn rv;
|
|
QStringList exportersList;
|
|
QMap<QString, const aiExportFormatDesc*> exportersMap;
|
|
|
|
|
|
if(mScene == nullptr)
|
|
{
|
|
QMessageBox::critical(this, "Export error", "Scene is empty");
|
|
|
|
return;
|
|
}
|
|
|
|
for (size_t i = 0; i < exporter.GetExportFormatCount(); ++i)
|
|
{
|
|
const aiExportFormatDesc* desc = exporter.GetExportFormatDescription(i);
|
|
exportersList.push_back(desc->id + QString(": ") + desc->description);
|
|
exportersMap.insert(desc->id, desc);
|
|
}
|
|
|
|
// get an exporter
|
|
bool dialogSelectExporterOk;
|
|
QString selectedExporter = QInputDialog::getItem(this, "Export format", "Select the exporter : ", exportersList, 0, false, &dialogSelectExporterOk);
|
|
if (!dialogSelectExporterOk)
|
|
return;
|
|
|
|
// build the filter
|
|
QString selectedId = selectedExporter.left(selectedExporter.indexOf(':'));
|
|
filter = QString("*.") + exportersMap[selectedId]->fileExtension;
|
|
|
|
// get file path
|
|
filename = QFileDialog::getSaveFileName(this, "Set file name", "", filter);
|
|
// if it's canceled
|
|
if (filename == "")
|
|
return;
|
|
|
|
// begin export
|
|
time_begin = QTime::currentTime();
|
|
rv = exporter.Export(mScene, selectedId.toLocal8Bit(), filename.toLocal8Bit(), aiProcess_FlipUVs);
|
|
ui->lblExportTime->setText(QString::number(time_begin.secsTo(QTime::currentTime())));
|
|
if(rv == aiReturn_SUCCESS)
|
|
LogInfo("Export done: " + filename);
|
|
else
|
|
{
|
|
QString errorMessage = QString("Export failed: ") + filename;
|
|
LogError(errorMessage);
|
|
QMessageBox::critical(this, "Export error", errorMessage);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void MainWindow::on_cbxLighting_clicked(bool pChecked)
|
|
{
|
|
if(pChecked)
|
|
mGLView->Lighting_Enable();
|
|
else
|
|
mGLView->Lighting_Disable();
|
|
|
|
mGLView->update();
|
|
}
|
|
|
|
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());
|
|
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
|
|
void MainWindow::on_lstCamera_clicked( const QModelIndex &)
|
|
{
|
|
mGLView->Camera_Set(ui->lstLight->currentRow());
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
|
|
void MainWindow::on_cbxBBox_clicked(bool checked)
|
|
{
|
|
mGLView->Enable_SceneBBox(checked);
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
|
|
void MainWindow::on_cbxDrawAxes_clicked(bool checked)
|
|
{
|
|
mGLView->Enable_Axes(checked);
|
|
#if ASSIMP_QT4_VIEWER
|
|
mGLView->updateGL();
|
|
#else
|
|
mGLView->update();
|
|
#endif // ASSIMP_QT4_VIEWER
|
|
}
|
|
|
|
void MainWindow::on_cbxTextures_clicked(bool checked)
|
|
{
|
|
mGLView->Enable_Textures(checked);
|
|
mGLView->update();
|
|
}
|