diff --git a/MeshViewerQt/Header/FileInterface.h b/MeshViewerQt/Header/FileInterface.h new file mode 100644 index 0000000..bcc2f15 --- /dev/null +++ b/MeshViewerQt/Header/FileInterface.h @@ -0,0 +1,72 @@ +#pragma once +#include +#include +#include + +//TODO: shouldn't be here +enum ModelTyp { + null, + dynamicMesh, + cloth, + bone, + staticMesh, + shadowMesh = 6 +}; + +struct BoundingBox { + float quaternion[4]; + float center[3]; + float extents[3]; +}; + +struct Segment { + std::uint32_t textureIndex = 0; + float* vertex = nullptr; + float* uv = nullptr; + std::vector> polyIndices; // indices into vertex array +}; + +struct Model { + std::string name = ""; + std::string parent = ""; + ModelTyp type = null; //TODO: should be removed + std::int32_t renderFlags = -1; //TODO: should be removed + QMatrix4x4 m4x4Translation; + std::vector segmList; +}; + +class FileInterface +{ +public: + FileInterface(const char* path) + : m_vModels(new std::vector) + { + //open file + m_fsMesh.open(path, std::ios::in | std::ios::binary); + + if (!m_fsMesh.is_open()) + throw std::invalid_argument(std::string("file not found: ") += path); + }; + + virtual ~FileInterface() + { + // close file + m_fsMesh.close(); + + //clean up + m_vTextureNames.clear(); + }; + +protected: + std::vector* m_vModels; + std::fstream m_fsMesh; + std::vector m_vTextureNames; + BoundingBox m_sceneBbox; + + virtual void import() = 0; + +public: + virtual std::vector* getModels() const { return m_vModels; }; + virtual std::vector getTextureNames() const { return m_vTextureNames; }; + virtual BoundingBox getBoundingBox() const { return m_sceneBbox; }; +}; \ No newline at end of file diff --git a/MeshViewerQt/Header/MainWindow.h b/MeshViewerQt/Header/MainWindow.h index 2d0a131..ca011cd 100644 --- a/MeshViewerQt/Header/MainWindow.h +++ b/MeshViewerQt/Header/MainWindow.h @@ -18,6 +18,7 @@ private: // Functions private: void setupWindow(); + void import(const char* path); // Slots private slots: diff --git a/MeshViewerQt/Header/MshFile.h b/MeshViewerQt/Header/MshFile.h index 1bc59e5..4fdf953 100644 --- a/MeshViewerQt/Header/MshFile.h +++ b/MeshViewerQt/Header/MshFile.h @@ -1,22 +1,6 @@ #pragma once -#include -#include -#include +#include "FileInterface.h" -enum ModelTyp { - null, - dynamicMesh, - cloth, - bone, - staticMesh, - shadowMesh = 6 -}; - -struct BoundingBox { - float quaternion[4]; - float center[3]; - float extents[3]; -}; struct ChunkHeader { char name[5]; @@ -24,36 +8,16 @@ struct ChunkHeader { std::streampos position; }; -struct Segment { - std::uint32_t textureIndex = 0; - float* vertex = nullptr; - float* uv = nullptr; - std::vector> polyIndices; // indices into vertex array -}; -struct Model { - std::string name = ""; - std::string parent = ""; - ModelTyp type = null; - std::int32_t renderFlags = -1; - QMatrix4x4 m4x4Translation; - std::vector segmList; -}; - - -class MshFile +class MshFile : public FileInterface { public: MshFile(const char* path); ~MshFile(); private: - std::vector* m_vModels; - std::fstream m_fsMesh; - std::vector m_vTextureNames; - BoundingBox m_sceneBbox; + virtual void import() override final; -private: void loadChunks(std::list &destination, std::streampos start, const std::uint32_t length); void analyseMsh2Chunks(std::list &chunkList); @@ -67,9 +31,4 @@ private: void readVertex(Segment* dataDestination, std::streampos position); void readUV(Segment* dataDestination, std::streampos position); - -public: - std::vector* getModels() const; - std::vector getTextureNames() const; - BoundingBox getBoundingBox() const; }; \ No newline at end of file diff --git a/MeshViewerQt/Header/OpenGlViewer.h b/MeshViewerQt/Header/OpenGlViewer.h index b7ccc44..fe260b5 100644 --- a/MeshViewerQt/Header/OpenGlViewer.h +++ b/MeshViewerQt/Header/OpenGlViewer.h @@ -6,7 +6,7 @@ #include #include #include -#include "..\Header\MshFile.h" +#include "..\Header\FileInterface.h" struct Vertex { GLfloat position[3]; @@ -30,8 +30,8 @@ private: QOpenGLShaderProgram* m_program = nullptr; // Data ======================================== - std::vector* m_vModels = nullptr; - std::vector m_vTextures; + std::vector* m_vModels = nullptr; + std::vector* m_vTextures = nullptr; BoundingBox m_sceneBoundings; // Transformation ============================== @@ -49,13 +49,13 @@ private: private: virtual void initializeGL() override final; - virtual void resizeGL(int w, int h) override final; virtual void paintGL() override final; void printContextInformation(); + QMatrix4x4 getModelMatrix(unsigned int index) const; QMatrix4x4 getMVPMatrix(unsigned int index) const; void deleteData(); public: - void setData(std::vector* models, std::vector textures); + void setData(std::vector* models, std::vector* textures, BoundingBox bbox); }; diff --git a/MeshViewerQt/Source/MainWindow.cpp b/MeshViewerQt/Source/MainWindow.cpp index 7a740ca..2c9b205 100644 --- a/MeshViewerQt/Source/MainWindow.cpp +++ b/MeshViewerQt/Source/MainWindow.cpp @@ -1,8 +1,10 @@ #include "..\Header\MainWindow.h" #include "..\Header\OpenGlViewer.h" +#include "..\Header\MshFile.h" #include "..\Header\defines.h" #include #include +#include ///////////////////////////////////////////////////////////////////////// @@ -34,18 +36,85 @@ void MainWindow::setupWindow() this->setCentralWidget(new OpenGlViewer(this)); + ui->mainToolBar->addAction("Open File", this, &MainWindow::openFile); ui->mainToolBar->addAction("File Info", this, &MainWindow::aboutFile); ui->statusBar->showMessage(DEFAULT_STATUS_MESSAGE); } +void MainWindow::import(const char * path) +{ + try + { + MshFile file(path); + + // Models + std::vector* tmp_models = file.getModels(); + + // Textures + std::vector tmp_texNames = file.getTextureNames(); + std::vector* tmp_textures = new std::vector; + + std::string tmp_path = path; + + while (tmp_path.back() != '/' && tmp_path.back() != '\\') + tmp_path.pop_back(); + + for (auto& it : tmp_texNames) + { + QImage* tmp_image = new QImage; + + std::string test = tmp_path + it; + QString test2 = "D:\\workspaces\\Visual Studio 2015\\Projects\\OpenGL\\Release\\Msh\\texture32R.tga"; + + if (tmp_image->load(test2)) + tmp_textures->push_back(tmp_image); + else + { + delete tmp_image; + tmp_image = new QImage(1, 1, QImage::Format_RGB32); + tmp_image->fill(Qt::red); + tmp_textures->push_back(tmp_image); + } + } + + // add a solid default color at the end (maybe there is an invalid index later) + QImage* tmp_image = new QImage(1, 1, QImage::Format_RGB16); + tmp_image->fill(Qt::red); + tmp_textures->push_back(tmp_image); + + tmp_texNames.clear(); + + // Bounding Box + BoundingBox tmp_bbox = file.getBoundingBox(); + + OpenGlViewer* tmp_viewer = dynamic_cast(centralWidget()); + + tmp_viewer->setData(tmp_models, tmp_textures, tmp_bbox); + + } + catch (std::invalid_argument e) + { + //TODO: + QMessageBox msg(this); + msg.addButton(QMessageBox::Ok); + msg.setText(QString::fromStdString(e.what())); + msg.setIcon(QMessageBox::Critical); + msg.setWindowTitle("Open File Error"); + + msg.exec(); + } +} + ///////////////////////////////////////////////////////////////////////// // private slots void MainWindow::openFile() { - //TODO: Open file + QString fileName = QFileDialog::getOpenFileName(this, "Open File", "../Release/Msh", "Mesh (*.msh)"); + + import(fileName.toStdString().c_str()); } void MainWindow::aboutFile() diff --git a/MeshViewerQt/Source/MshFile.cpp b/MeshViewerQt/Source/MshFile.cpp index 06a5110..a683cc5 100644 --- a/MeshViewerQt/Source/MshFile.cpp +++ b/MeshViewerQt/Source/MshFile.cpp @@ -10,14 +10,21 @@ // public constructor/destructor MshFile::MshFile(const char * path) - : m_vModels(new std::vector) + : FileInterface(path) { - //open file - m_fsMesh.open(path, std::ios::in | std::ios::binary); + import(); +} - if (!m_fsMesh.is_open()) - throw std::invalid_argument(std::string("file not found: ") += path); +MshFile::~MshFile() +{ +} + +///////////////////////////////////////////////////////////////////////// +// private functions + +void MshFile::import() +{ // go to file size information m_fsMesh.seekg(4); @@ -57,20 +64,8 @@ MshFile::MshFile(const char * path) tmp_mainChunks.pop_front(); delete cur; } - - // close file - m_fsMesh.close(); } -MshFile::~MshFile() -{ - m_vTextureNames.clear(); -} - - -///////////////////////////////////////////////////////////////////////// -// private functions - void MshFile::loadChunks(std::list& destination, std::streampos start, const std::uint32_t length) { // jump to first chunk @@ -572,22 +567,3 @@ void MshFile::readUV(Segment * dataDestination, std::streampos position) for (unsigned int i = 0; i < tmp_size * 2; i++) m_fsMesh.read(F2V(dataDestination->uv[i]), sizeof(float)); } - - -///////////////////////////////////////////////////////////////////////// -// public getter - -std::vector* MshFile::getModels() const -{ - return m_vModels; -} - -std::vector MshFile::getTextureNames() const -{ - return m_vTextureNames; -} - -BoundingBox MshFile::getBoundingBox() const -{ - return m_sceneBbox; -} diff --git a/MeshViewerQt/Source/OpenGlViewer.cpp b/MeshViewerQt/Source/OpenGlViewer.cpp index 73f4f12..96fb28a 100644 --- a/MeshViewerQt/Source/OpenGlViewer.cpp +++ b/MeshViewerQt/Source/OpenGlViewer.cpp @@ -1,5 +1,7 @@ #include "..\Header\OpenGlViewer.h" +#include #include +#include ///////////////////////////////////////////////////////////////////////// @@ -104,11 +106,6 @@ void OpenGlViewer::initializeGL() } -void OpenGlViewer::resizeGL(int w, int h) -{ - //TODO: change perspective -} - void OpenGlViewer::paintGL() { //TODO: paint here @@ -134,8 +131,8 @@ void OpenGlViewer::paintGL() for (auto& segmentIterator : m_vModels->at(modelIndex)->segmList) { // set the texture - std::uint32_t tmp_textureIndex = segmentIterator->textureIndex >= m_vTextures.size() ? m_vTextures.size() - 1 : segmentIterator->textureIndex; - m_oglTexture->setData(*m_vTextures.at(tmp_textureIndex)); + std::uint32_t tmp_textureIndex = segmentIterator->textureIndex >= m_vTextures->size() ? m_vTextures->size() - 1 : segmentIterator->textureIndex; + m_oglTexture->setData(*m_vTextures->at(tmp_textureIndex)); // give the MVP to the shader m_program->setUniformValue(m_uniformMVP, getMVPMatrix(modelIndex)); @@ -152,7 +149,7 @@ void OpenGlViewer::paintGL() } } } - //glDrawArrays(GL_TRIANGLES, 0, sizeof(sg_vertexes) / sizeof(sg_vertexes[0])); + m_oglTexture->release(); m_vertexArray.release(); m_program->release(); @@ -179,14 +176,50 @@ void OpenGlViewer::printContextInformation() std::cout << glType.toStdString() << " - " << glVersion.toStdString() << " (" << glProfile.toStdString() << ")"; } +QMatrix4x4 OpenGlViewer::getModelMatrix(unsigned int index) const +{ + QMatrix4x4 tmp_parent; + + for (unsigned int loop = 0; loop < m_vModels->size(); loop++) + { + if (!strcmp(m_vModels->at(index)->parent.c_str(), m_vModels->at(loop)->name.c_str())) + { + tmp_parent = getModelMatrix(loop); + break; + } + } + + return tmp_parent * m_vModels->at(index)->m4x4Translation; +} + QMatrix4x4 OpenGlViewer::getMVPMatrix(unsigned int index) const { - return QMatrix4x4(); + QMatrix4x4 tmp_mvp; + + // projection + tmp_mvp.perspective(m_fFOV, float(QWidget::width()) / float(QWidget::height()), m_fMinView, m_fMaxView); + + // view + tmp_mvp.lookAt(QVector3D(m_fTranX, m_fTranY, m_fTranZ), QVector3D(m_fTranX, m_fTranY, m_fTranZ - 1), QVector3D(0, 0, 1)); + + // user controlled rotation + tmp_mvp.rotate(m_fRotX, QVector3D(1, 0, 0)); + tmp_mvp.rotate(m_fRotY, QVector3D(0, 1, 0)); + tmp_mvp.rotate(m_fRotZ, QVector3D(0, 0, 1)); + + //scale to 1 + float maxExtent = std::max(std::max(m_sceneBoundings.extents[0], m_sceneBoundings.extents[1]), m_sceneBoundings.extents[2]); + tmp_mvp.scale(1 / maxExtent); + + // move to center + tmp_mvp.translate(-m_sceneBoundings.center[0], -m_sceneBoundings.center[1], -m_sceneBoundings.center[2]); + + return tmp_mvp * getModelMatrix(index); } void OpenGlViewer::deleteData() { - if (m_vModels != NULL) + if (m_vModels != nullptr) { while (!m_vModels->empty()) { @@ -223,17 +256,19 @@ void OpenGlViewer::deleteData() delete m_vModels; } - while (!m_vTextures.empty()) + if (m_vTextures != nullptr) { - // remove the last texture - QImage* cursor = m_vTextures.back(); - m_vTextures.pop_back(); + while (!m_vTextures->empty()) + { + // remove the last texture + QImage* cursor = m_vTextures->back(); + m_vTextures->pop_back(); - //delete image - delete cursor; - - //delete the texture - delete cursor; + //delete image + delete cursor; + } + // delete the Textrue's Vector + delete m_vTextures; } } @@ -241,9 +276,73 @@ void OpenGlViewer::deleteData() ///////////////////////////////////////////////////////////////////////// // public functions -void OpenGlViewer::setData(std::vector* models, std::vector textures) +void OpenGlViewer::setData(std::vector* models, std::vector* textures, BoundingBox bbox) { + // new Data, so clean up the old things + deleteData(); + + // save the variables m_vModels = models; m_vTextures = textures; -} + m_sceneBoundings = bbox; + // collect vertex data of all models + std::vector tmp_bufferData; + + for (auto& modIt : *m_vModels) // for every model chunk + { + for (auto& segIt : modIt->segmList) // for every cluster + { + for (auto& mshIt : segIt->polyIndices) // for every polygon + { + if (mshIt.size() >= 3) // multipoly + { + // for every triangle of the multi polygon + for (unsigned int tri = 0; tri < mshIt.size() - 2; tri++) + { + // for every edge of the triangle + for (int triEdge = 0; triEdge < 3; triEdge++) + { + Vertex tempVertex; + // every edge has 3 coordinates + for (int j = 0; j < 3; j++) + tempVertex.position[j] = (GLfloat)segIt->vertex[mshIt[tri + triEdge - ((tri % 2) * (triEdge - 1) * 2)] * 3 + j]; + + // and 2 UV + if (segIt->uv == NULL) + { + tempVertex.uv[0] = 1.0; + tempVertex.uv[1] = 1.0; + } + else + { + for (int j = 0; j < 2; j++) + tempVertex.uv[j] = (GLfloat)segIt->uv[mshIt[tri + triEdge - ((tri % 2) * (triEdge - 1) * 2)] * 2 + j]; + } + tmp_bufferData.push_back(tempVertex); + } + } + } + else // this shouldn't happen (polygon with less then 3 vertex) + { + deleteData(); + + QMessageBox msg(this); + msg.addButton(QMessageBox::Ok); + msg.setText("You have polygons with less then 3 vertices!"); + msg.setIcon(QMessageBox::Critical); + msg.setWindowTitle("Open File Error"); + msg.exec(); + return; + } + } + } + } + + + m_vertexBuffer.bind(); + m_vertexBuffer.allocate(tmp_bufferData.data(), sizeof(Vertex) * tmp_bufferData.size()); + m_vertexBuffer.release(); + + tmp_bufferData.clear(); +}