From fb49d8685a27cd5c2c9319ccc19c9ad1855c42c3 Mon Sep 17 00:00:00 2001 From: Anakin Date: Thu, 26 Jan 2017 18:17:54 +0100 Subject: [PATCH] switch from QLineEdit to QSpinBox, init SettingsWindow with default values from OglViewerWidget, removed old qt project --- MeshViewerQt/Form Files/MainWindow.ui | 35 -- MeshViewerQt/Header/FileInterface.h | 72 --- MeshViewerQt/Header/MainWindow.h | 32 -- MeshViewerQt/Header/MshFile.h | 34 -- MeshViewerQt/Header/OpenGlViewer.h | 67 --- MeshViewerQt/Header/Texture.h | 22 - MeshViewerQt/Header/defines.h | 8 - MeshViewerQt/Resources/MainWindow.qrc | 11 - MeshViewerQt/Resources/TextureShader.frag | 12 - MeshViewerQt/Resources/TextureShader.vert | 17 - MeshViewerQt/Resources/icon.ico | Bin 270398 -> 0 bytes MeshViewerQt/Resources/simple.frag | 8 - MeshViewerQt/Resources/simple.vert | 10 - MeshViewerQt/Source/MainWindow.cpp | 151 ------ MeshViewerQt/Source/MshFile.cpp | 569 ---------------------- MeshViewerQt/Source/OpenGlViewer.cpp | 372 -------------- MeshViewerQt/Source/Texture.cpp | 119 ----- MeshViewerQt/main.cpp | 18 - QtMeshViewer/Form Files/SettingsWindow.ui | 83 ++-- QtMeshViewer/Header/SettingsWindow.h | 4 +- QtMeshViewer/Source/OglViewerWidget.cpp | 3 +- QtMeshViewer/Source/SettingsWindow.cpp | 99 ++-- 22 files changed, 124 insertions(+), 1622 deletions(-) delete mode 100644 MeshViewerQt/Form Files/MainWindow.ui delete mode 100644 MeshViewerQt/Header/FileInterface.h delete mode 100644 MeshViewerQt/Header/MainWindow.h delete mode 100644 MeshViewerQt/Header/MshFile.h delete mode 100644 MeshViewerQt/Header/OpenGlViewer.h delete mode 100644 MeshViewerQt/Header/Texture.h delete mode 100644 MeshViewerQt/Header/defines.h delete mode 100644 MeshViewerQt/Resources/MainWindow.qrc delete mode 100644 MeshViewerQt/Resources/TextureShader.frag delete mode 100644 MeshViewerQt/Resources/TextureShader.vert delete mode 100644 MeshViewerQt/Resources/icon.ico delete mode 100644 MeshViewerQt/Resources/simple.frag delete mode 100644 MeshViewerQt/Resources/simple.vert delete mode 100644 MeshViewerQt/Source/MainWindow.cpp delete mode 100644 MeshViewerQt/Source/MshFile.cpp delete mode 100644 MeshViewerQt/Source/OpenGlViewer.cpp delete mode 100644 MeshViewerQt/Source/Texture.cpp delete mode 100644 MeshViewerQt/main.cpp diff --git a/MeshViewerQt/Form Files/MainWindow.ui b/MeshViewerQt/Form Files/MainWindow.ui deleted file mode 100644 index 739421a..0000000 --- a/MeshViewerQt/Form Files/MainWindow.ui +++ /dev/null @@ -1,35 +0,0 @@ - - - MainWindowClass - - - - 0 - 0 - 600 - 400 - - - - MainWindow - - - - - false - - - TopToolBarArea - - - false - - - - - - - - - - diff --git a/MeshViewerQt/Header/FileInterface.h b/MeshViewerQt/Header/FileInterface.h deleted file mode 100644 index bcc2f15..0000000 --- a/MeshViewerQt/Header/FileInterface.h +++ /dev/null @@ -1,72 +0,0 @@ -#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 deleted file mode 100644 index ca011cd..0000000 --- a/MeshViewerQt/Header/MainWindow.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include "ui_MainWindow.h" - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - MainWindow(QWidget *parent = Q_NULLPTR); - ~MainWindow(); - -// Variables -private: - Ui::MainWindowClass* ui; - -// Functions -private: - void setupWindow(); - void import(const char* path); - -// Slots -private slots: - void openFile(); - void aboutFile(); - - -// Override Functions -protected: - virtual void keyPressEvent(QKeyEvent * keyEvent) override final; -}; diff --git a/MeshViewerQt/Header/MshFile.h b/MeshViewerQt/Header/MshFile.h deleted file mode 100644 index 4fdf953..0000000 --- a/MeshViewerQt/Header/MshFile.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "FileInterface.h" - - -struct ChunkHeader { - char name[5]; - std::uint32_t size; - std::streampos position; -}; - - -class MshFile : public FileInterface -{ -public: - MshFile(const char* path); - ~MshFile(); - -private: - virtual void import() override final; - - void loadChunks(std::list &destination, std::streampos start, const std::uint32_t length); - - void analyseMsh2Chunks(std::list &chunkList); - - void analyseMatdChunks(std::list &chunkList); - - void analyseModlChunks(Model* dataDestination, std::list &chunkList); - void analyseGeomChunks(Model* dataDestination, std::list &chunkList); - void analyseSegmChunks(Model* dataDestination, std::list &chunkList); - void analyseClthChunks(Model* dataDestination, std::list &chunkList); - - void readVertex(Segment* dataDestination, std::streampos position); - void readUV(Segment* dataDestination, std::streampos position); -}; \ No newline at end of file diff --git a/MeshViewerQt/Header/OpenGlViewer.h b/MeshViewerQt/Header/OpenGlViewer.h deleted file mode 100644 index 8f91453..0000000 --- a/MeshViewerQt/Header/OpenGlViewer.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "..\Header\Texture.h" -#include "..\Header\FileInterface.h" - -struct Vertex { - GLfloat position[3]; - GLfloat uv[2]; -}; - -struct TextureData { - bool alpha; - std::uint32_t width; - std::uint32_t height; - std::vector* data; -}; - -class OpenGlViewer : public QOpenGLWidget, protected QOpenGLFunctions -{ - Q_OBJECT - -public: - OpenGlViewer(QWidget *parent); - ~OpenGlViewer(); - -private: -// OpenGL ====================================== - int m_uniformMVP; - GLuint m_oglTexture; - GLuint m_vertexBuffer; - QOpenGLVertexArrayObject m_vertexArray; - QOpenGLShaderProgram* m_program = nullptr; - -// Data ======================================== - std::vector* m_vModels = nullptr; - std::vector* m_vTextures = nullptr; - BoundingBox m_sceneBoundings; - -// Transformation ============================== - float m_fRotX = 0; - float m_fRotY = 0; - float m_fRotZ = 0; - float m_fTranX = 0; - float m_fTranY = 0; - float m_fTranZ = 0; - -// Camera ====================================== - float m_fFOV = 45.0f; - float m_fMinView = 0.1f; - float m_fMaxView = 100.0f; - -private: - virtual void initializeGL() 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, BoundingBox bbox); -}; diff --git a/MeshViewerQt/Header/Texture.h b/MeshViewerQt/Header/Texture.h deleted file mode 100644 index cd56653..0000000 --- a/MeshViewerQt/Header/Texture.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include - - -class TextureTGA -{ -public: - TextureTGA(const char* filePath); - ~TextureTGA(); - -private: - std::vector* vui8Pixels; - std::uint32_t ui32BpP; - std::uint32_t ui32Width; - std::uint32_t ui32Height; - -public: - std::vector* getData() const; - bool hasAlpha() const; - std::uint32_t getWidth() const; - std::uint32_t getHeight() const; -}; diff --git a/MeshViewerQt/Header/defines.h b/MeshViewerQt/Header/defines.h deleted file mode 100644 index cbf9149..0000000 --- a/MeshViewerQt/Header/defines.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#define WINDOW_NAME "Mesh Viewer" -#define WINDOW_WIDTH 640 -#define WINDOW_HEIGHT 480 - -#define DEFAULT_STATUS_MESSAGE "Mesh Viewer pre alpha by Anakin" - diff --git a/MeshViewerQt/Resources/MainWindow.qrc b/MeshViewerQt/Resources/MainWindow.qrc deleted file mode 100644 index 3d2b578..0000000 --- a/MeshViewerQt/Resources/MainWindow.qrc +++ /dev/null @@ -1,11 +0,0 @@ - - - icon.ico - - - simple.frag - simple.vert - TextureShader.frag - TextureShader.vert - - diff --git a/MeshViewerQt/Resources/TextureShader.frag b/MeshViewerQt/Resources/TextureShader.frag deleted file mode 100644 index 3c9924a..0000000 --- a/MeshViewerQt/Resources/TextureShader.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 330 - -// Input -in vec2 UV; - -// Output -out vec4 color; - -void main() -{ - color = {255,0,0};//texture(textureSampler, UV).rgb; -} \ No newline at end of file diff --git a/MeshViewerQt/Resources/TextureShader.vert b/MeshViewerQt/Resources/TextureShader.vert deleted file mode 100644 index b8865eb..0000000 --- a/MeshViewerQt/Resources/TextureShader.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 - -// Input vertex data, different for all executions of this shader -layout(location = 0) in vec3 vertexPosition; -layout(location = 1) in vec3 vertexUV; - -// Input that stay constant fpr the whole mesh -uniform mat4 MVP; - -// Output -out vec2 UV; - -void main() -{ - gl_Position = MVP * vec4(vertexPosition, 1); - UV = vertexUV; -} \ No newline at end of file diff --git a/MeshViewerQt/Resources/icon.ico b/MeshViewerQt/Resources/icon.ico deleted file mode 100644 index 3a2186f250235aa317c4f2138818e46d07b4a504..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 270398 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 SdCG2hh~`7ItgE(C4g7yhEfLZH diff --git a/MeshViewerQt/Resources/simple.frag b/MeshViewerQt/Resources/simple.frag deleted file mode 100644 index 9844eff..0000000 --- a/MeshViewerQt/Resources/simple.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 330 -in vec4 vColor; -out vec4 fColor; - -void main() -{ - fColor = vColor; -} \ No newline at end of file diff --git a/MeshViewerQt/Resources/simple.vert b/MeshViewerQt/Resources/simple.vert deleted file mode 100644 index fad59f5..0000000 --- a/MeshViewerQt/Resources/simple.vert +++ /dev/null @@ -1,10 +0,0 @@ -#version 330 -layout(location = 0) in vec3 position; -layout(location = 1) in vec3 color; -out vec4 vColor; - -void main() -{ - gl_Position = vec4(position, 1.0); - vColor = vec4(color, 1.0); -} \ No newline at end of file diff --git a/MeshViewerQt/Source/MainWindow.cpp b/MeshViewerQt/Source/MainWindow.cpp deleted file mode 100644 index 2148647..0000000 --- a/MeshViewerQt/Source/MainWindow.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "..\Header\MainWindow.h" -#include "..\Header\OpenGlViewer.h" -#include "..\Header\MshFile.h" -#include "..\Header\defines.h" -#include -#include -#include - - -///////////////////////////////////////////////////////////////////////// -// constructor/destructor - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) - , ui (new Ui::MainWindowClass) -{ - setupWindow(); -} - -MainWindow::~MainWindow() -{ - delete ui; -} - - -///////////////////////////////////////////////////////////////////////// -// private functions - -void MainWindow::setupWindow() -{ - ui->setupUi(this); - - this->setWindowTitle(WINDOW_NAME); - this->setWindowIcon(QIcon(":/MainWindow/icon.ico")); - this->resize(WINDOW_WIDTH, WINDOW_HEIGHT); - - 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) -{ - // variables - std::vector* tmp_models = nullptr; - std::vector* tmp_textures = new std::vector; - std::vector tmp_texNames; - BoundingBox tmp_bbox; - - // model file - try - { - MshFile file(path); - tmp_models = file.getModels(); - tmp_texNames = file.getTextureNames(); - tmp_bbox = file.getBoundingBox(); - } - catch (std::invalid_argument e) - { - QMessageBox msg(this); - msg.addButton(QMessageBox::Ok); - msg.setText(QString::fromStdString(e.what())); - msg.setIcon(QMessageBox::Critical); - msg.setWindowTitle("Open File Error"); - - msg.exec(); - return; - } - - // parth to texture - std::string tmp_path = path; - while (tmp_path.back() != '/' && tmp_path.back() != '\\') - tmp_path.pop_back(); - - // load all textures - for (auto& texIt : tmp_texNames) - { - TextureData* new_data = new TextureData; - try - { - TextureTGA tmp_texFile(std::string(tmp_path + texIt).c_str()); - - new_data->alpha = tmp_texFile.hasAlpha(); - new_data->width = tmp_texFile.getWidth(); - new_data->height = tmp_texFile.getHeight(); - new_data->data = tmp_texFile.getData(); - } - catch (std::invalid_argument e) - { - new_data->alpha = true; - new_data->width = 1; - new_data->height = 1; - new_data->data = new std::vector({ 0, 0, 255, 255 }); - } - - tmp_textures->push_back(new_data); - } - - // add a solid default color at the end (maybe there is an invalid index later) - TextureData* new_data = new TextureData; - new_data->alpha = true; - new_data->width = 1; - new_data->height = 1; - new_data->data = new std::vector({ 0, 0, 255, 255 }); - tmp_textures->push_back(new_data); - - // clean up texture name list - tmp_texNames.clear(); - - // give the data to the viewer - OpenGlViewer* tmp_viewer = dynamic_cast(centralWidget()); - tmp_viewer->setData(tmp_models, tmp_textures, tmp_bbox); -} - - -///////////////////////////////////////////////////////////////////////// -// private slots - -void MainWindow::openFile() -{ - QString fileName = QFileDialog::getOpenFileName(this, "Open File", "../Release/Msh", "Mesh (*.msh)"); - - import(fileName.toStdString().c_str()); -} - -void MainWindow::aboutFile() -{ - //TODO: Open Window with file information - QMessageBox* dialog = new QMessageBox(QMessageBox::Information, WINDOW_NAME, "File Info", QMessageBox::StandardButton::Close, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); - dialog->setDetailedText("This is the cool detailed text\n"); - dialog->exec(); -} - - -///////////////////////////////////////////////////////////////////////// -// events - -void MainWindow::keyPressEvent(QKeyEvent * keyEvent) -{ - switch (keyEvent->key()) - { - case Qt::Key::Key_Escape: - close(); - break; - } - - QMainWindow::keyPressEvent(keyEvent); -} diff --git a/MeshViewerQt/Source/MshFile.cpp b/MeshViewerQt/Source/MshFile.cpp deleted file mode 100644 index a683cc5..0000000 --- a/MeshViewerQt/Source/MshFile.cpp +++ /dev/null @@ -1,569 +0,0 @@ -#include "..\Header\MshFile.h" -#include - - -// helper function to save data from file to any variable type -#define F2V(variableName) reinterpret_cast(&variableName) - - -///////////////////////////////////////////////////////////////////////// -// public constructor/destructor - -MshFile::MshFile(const char * path) - : FileInterface(path) -{ - import(); -} - -MshFile::~MshFile() -{ -} - - -///////////////////////////////////////////////////////////////////////// -// private functions - -void MshFile::import() -{ - // go to file size information - m_fsMesh.seekg(4); - - std::uint32_t tmp_fileSize; - std::list tmp_mainChunks; - - // get all chunks under HEDR - m_fsMesh.read(F2V(tmp_fileSize), sizeof(tmp_fileSize)); - loadChunks(tmp_mainChunks, m_fsMesh.tellg(), tmp_fileSize); - - // evaulate HEDR subchunks (= find MSH2) - for (ChunkHeader* it : tmp_mainChunks) - { - if (!strcmp("MSH2", it->name)) - { - // get all subchunks - std::list tmp_msh2Chunks; - loadChunks(tmp_msh2Chunks, it->position, it->size); - - // evaluate MSH2 subchunks - analyseMsh2Chunks(tmp_msh2Chunks); - - // clean up - while (!tmp_msh2Chunks.empty()) - { - ChunkHeader* curs = tmp_msh2Chunks.front(); - tmp_msh2Chunks.pop_front(); - delete curs; - } - } - } - - // clean up - while (!tmp_mainChunks.empty()) - { - ChunkHeader* cur = tmp_mainChunks.front(); - tmp_mainChunks.pop_front(); - delete cur; - } -} - -void MshFile::loadChunks(std::list& destination, std::streampos start, const std::uint32_t length) -{ - // jump to first chunk - m_fsMesh.seekg(start); - - do - { - ChunkHeader* tmp_header = new ChunkHeader(); - - // get information - m_fsMesh.read(F2V(tmp_header->name[0]), sizeof(tmp_header->name) - 1); - m_fsMesh.read(F2V(tmp_header->size), sizeof(tmp_header->size)); - tmp_header->position = m_fsMesh.tellg(); - - // store information - destination.push_back(tmp_header); - - // jump to next header - m_fsMesh.seekg(tmp_header->size, std::ios_base::cur); - - // out of file. Maybe a size information is corrupted - if (!m_fsMesh.good()) - { - //TODO: different way for output - std::cout << "WARNING: corrupted file. Trying to continue" << std::endl; - m_fsMesh.clear(); - break; - } - - } while (m_fsMesh.tellg() - start != length); -} - -void MshFile::analyseMsh2Chunks(std::list& chunkList) -{ - for (auto& it : chunkList) - { - // scene information - if (!strcmp("SINF", it->name)) - { - // get SINF subchunks - std::list tmp_sinfChunks; - loadChunks(tmp_sinfChunks, it->position, it->size); - - // evaluate SINF subchunks - for (auto& it : tmp_sinfChunks) - { - if (!strcmp("BBOX", it->name)) - { - m_fsMesh.seekg(it->position); - - // read in the quaternion - for (int i = 0; i < 4; i++) - m_fsMesh.read(F2V(m_sceneBbox.quaternion[i]), sizeof(float)); - - //read in the center - for (int i = 0; i < 3; i++) - m_fsMesh.read(F2V(m_sceneBbox.center[i]), sizeof(float)); - - //read in the extents - for (int i = 0; i < 3; i++) - m_fsMesh.read(F2V(m_sceneBbox.extents[i]), sizeof(float)); - } - } - - // clean up SINF subchunks - for (ChunkHeader* it : tmp_sinfChunks) - delete it; - } - - // material list - else if (!strcmp("MATL", it->name)) - { - // "useless" information how many MATD follow, jump over it - m_fsMesh.seekg(it->position); - m_fsMesh.seekg(sizeof(std::uint32_t), std::ios_base::cur); - - // get all MATL subchunk - std::list tmp_matlChunks; - loadChunks(tmp_matlChunks, m_fsMesh.tellg(), it->size - 4); - - // evaluate MATL subchunks - for (auto& it : tmp_matlChunks) - { - // This shouldn't be anything else than MATD - if (!strcmp("MATD", it->name)) - { - // get all subchunks from MATD - std::list tmp_matdChunks; - loadChunks(tmp_matdChunks, it->position, it->size); - - m_vTextureNames.push_back(""); - - // analyse MATD subchunks - analyseMatdChunks(tmp_matdChunks); - - // clean up MATD subchunks - while (!tmp_matdChunks.empty()) - { - ChunkHeader* cur = tmp_matdChunks.front(); - tmp_matdChunks.pop_front(); - delete cur; - } - } - } - - // clean up MATL subchunks - while (!tmp_matlChunks.empty()) - { - ChunkHeader* cur = tmp_matlChunks.front(); - tmp_matlChunks.pop_front(); - delete cur; - } - } - - // model - else if (!strcmp("MODL", it->name)) - { - Model* new_model = new Model; - - // get all MODL subchunks - std::list tmp_chunks; - loadChunks(tmp_chunks, it->position, it->size); - - // evaluate MODL subchunks - analyseModlChunks(new_model, tmp_chunks); - - //clean up MODL subchunks - while (!tmp_chunks.empty()) - { - ChunkHeader* cur = tmp_chunks.front(); - tmp_chunks.pop_front(); - delete cur; - } - - // save Model data - m_vModels->push_back(new_model); - } - } -} - -void MshFile::analyseMatdChunks(std::list& chunkList) -{ - for (auto& it : chunkList) - { - if (!strcmp("TX0D", it->name)) - { - m_fsMesh.seekg(it->position); - char* buffer = new char[it->size + 1]; - *buffer = { 0 }; - m_fsMesh.read(buffer, it->size); - m_vTextureNames.back() = buffer; - delete[] buffer; - } - } -} - -void MshFile::analyseModlChunks(Model * dataDestination, std::list& chunkList) -{ - for (auto& it : chunkList) - { - // model type - if (!strcmp("MTYP", it->name)) - { - m_fsMesh.seekg(it->position); - std::uint32_t tmp_type; - m_fsMesh.read(F2V(tmp_type), sizeof(tmp_type)); - dataDestination->type = (ModelTyp)tmp_type; - } - - // parent name - else if (!strcmp("PRNT", it->name)) - { - m_fsMesh.seekg(it->position); - char* buffer = new char[it->size + 1]; - *buffer = { 0 }; - m_fsMesh.read(buffer, it->size); - dataDestination->parent = buffer; - delete[] buffer; - } - - // model name - else if (!strcmp("NAME", it->name)) - { - m_fsMesh.seekg(it->position); - char* buffer = new char[it->size + 1]; - *buffer = { 0 }; - m_fsMesh.read(buffer, it->size); - dataDestination->name = buffer; - delete[] buffer; - } - - // render flags - else if (!strcmp("FLGS", it->name)) - { - m_fsMesh.seekg(it->position); - m_fsMesh.read(F2V(dataDestination->renderFlags), sizeof(dataDestination->renderFlags)); - } - - // translation - else if (!strcmp("TRAN", it->name)) - { - float tmp_scale[3]; - float tmp_rotation[4]; - float tmp_trans[3]; - - m_fsMesh.seekg(it->position); - - // read in the data - for (int i = 0; i < 3; i++) - m_fsMesh.read(F2V(tmp_scale[i]), sizeof(float)); - - for (int i = 0; i < 4; i++) - m_fsMesh.read(F2V(tmp_rotation[i]), sizeof(float)); - - for (int i = 0; i < 3; i++) - m_fsMesh.read(F2V(tmp_trans[i]), sizeof(float)); - - // modify the matrix - dataDestination->m4x4Translation.scale(tmp_scale[0], tmp_scale[1], tmp_scale[2]); - dataDestination->m4x4Translation.rotate(QQuaternion(tmp_rotation[3], tmp_rotation[0], tmp_rotation[1], tmp_rotation[2])); - dataDestination->m4x4Translation.translate(tmp_trans[0], tmp_trans[1], tmp_trans[2]); - - } - - // geometry data - else if (!strcmp("GEOM", it->name)) - { - // get all GEOM subchunks - std::list tmp_geomChunks; - loadChunks(tmp_geomChunks, it->position, it->size); - - // evaluate GEOM subchunks - analyseGeomChunks(dataDestination, tmp_geomChunks); - - // clean up GEOM subchunks - while (!tmp_geomChunks.empty()) - { - ChunkHeader* cur = tmp_geomChunks.front(); - tmp_geomChunks.pop_front(); - delete cur; - } - } - } -} - -void MshFile::analyseGeomChunks(Model * dataDestination, std::list& chunkList) -{ - for (auto& it : chunkList) - { - // segment - if (!strcmp("SEGM", it->name)) - { - // get all SEGM subchunks - std::list tmp_segmChunks; - loadChunks(tmp_segmChunks, it->position, it->size); - - // evaluate SEGM subchunks - analyseSegmChunks(dataDestination, tmp_segmChunks); - - // clean up SEGM subchunk - while (!tmp_segmChunks.empty()) - { - ChunkHeader* cur = tmp_segmChunks.front(); - tmp_segmChunks.pop_front(); - delete cur; - } - } - - // cloth - else if (!strcmp("CLTH", it->name)) - { - // get all CLTH subchunks - std::list tmp_clthChunks; - loadChunks(tmp_clthChunks, it->position, it->size); - - // evaluate CLTH subchunks - analyseClthChunks(dataDestination, tmp_clthChunks); - - // clean up CLTH subchunks - while (!tmp_clthChunks.empty()) - { - ChunkHeader* cur = tmp_clthChunks.front(); - tmp_clthChunks.pop_front(); - delete cur; - } - } - } -} - -void MshFile::analyseSegmChunks(Model * dataDestination, std::list& chunkList) -{ - Segment* new_segment = new Segment; - - for (auto& it : chunkList) - { - // material index - if (!strcmp("MATI", it->name)) - { - m_fsMesh.seekg(it->position); - m_fsMesh.read(F2V(new_segment->textureIndex), sizeof(new_segment->textureIndex)); - } - - // position list (vertex) - else if (!strcmp("POSL", it->name)) - { - readVertex(new_segment, it->position); - } - - // normals - /*else if (!strcmp("NRML", it->name)) - { - fsMesh.seekg(it->position); - std::uint32_t tempSize; - fsMesh.read(reinterpret_cast(&tempSize), sizeof(tempSize)); - // List of normals - // long int - 4 - number of normal vectores stored in this list - // float[3][] - 12 each - UVW vector for each vertex - }*/ - - // uv - else if (!strcmp("UV0L", it->name)) - { - readUV(new_segment, it->position); - } - - // polygons (indices into vertex/uv list) - else if (!strcmp("STRP", it->name)) - { - // don't get null, bone, shadowMesh and hidden mesh indices - if (dataDestination->type == null || - dataDestination->type == bone || - dataDestination->type == shadowMesh || - dataDestination->renderFlags == 1) - continue; - - // jump to the data section and read the size; - std::uint32_t tmp_size; - m_fsMesh.seekg(it->position); - m_fsMesh.read(F2V(tmp_size), sizeof(tmp_size)); - - int highBitCount(0); - std::vector new_poly; - - for (unsigned int i = 0; i < tmp_size; i++) - { - // ReadData - std::uint16_t tmp_value; - m_fsMesh.read(F2V(tmp_value), sizeof(tmp_value)); - - // Check if highbit is set - if (tmp_value >> 15) - { - highBitCount++; - // remove the high bit, to get the actually value - tmp_value = (std::uint16_t(tmp_value << 1) >> 1); - } - - // save data - new_poly.push_back((std::uint32_t)tmp_value); - - // if the last 2 highBits are set, it was a new poly - if (highBitCount == 2) - { - // reset highBitCount - highBitCount = 0; - - // remove the last two values.. - std::uint32_t temp[2]; - for (int i = 0; i < 2; i++) - { - temp[i] = new_poly.back(); - new_poly.pop_back(); - } - - // ..save the old polygon.. - new_segment->polyIndices.push_back(new_poly); - - // ..and move the values to a new polygon - new_poly.clear(); - for (int i = 1; i >= 0; i--) - new_poly.push_back(temp[i]); - - } // if high bit set - - } // for all values - - // save the last polygon (no 2 high bit followed) - new_segment->polyIndices.push_back(new_poly); - - // kick the first element, it's empty as a reason of the algo above; - new_segment->polyIndices.erase(new_segment->polyIndices.begin()); - } - } - - dataDestination->segmList.push_back(new_segment); -} - -void MshFile::analyseClthChunks(Model * dataDestination, std::list& chunkList) -{ - Segment* new_segment = new Segment; - - for (auto& it : chunkList) - { - // texture name - if (!strcmp("CTEX", it->name)) - { - // read the texture name - m_fsMesh.seekg(it->position); - char* buffer = new char[it->size + 1]; - *buffer = { 0 }; - m_fsMesh.read(buffer, it->size); - - // search if it is already known - bool tmp_found(false); - for (unsigned int i = 0; i < m_vTextureNames.size(); i++) - { - if (!strcmp(buffer, m_vTextureNames[i].c_str())) - { - // if found, save the index and stop searching - new_segment->textureIndex = i; - tmp_found = true; - break; - } - } - - // if it was not found add the texturename to the list - if (!tmp_found) - { - m_vTextureNames.push_back(std::string(buffer)); - new_segment->textureIndex = m_vTextureNames.size() - 1; - } - - delete[] buffer; - } - - // position list (vertex) - else if (!strcmp("CPOS", it->name)) - { - readVertex(new_segment, it->position); - } - - // uv - else if (!strcmp("CUV0", it->name)) - { - readUV(new_segment, it->position); - } - - // triangles (indices into vertex/uv list) - else if (!strcmp("CMSH", it->name)) - { - // jump to the data section and read the size; - std::uint32_t tmp_size; - m_fsMesh.seekg(it->position); - m_fsMesh.read(F2V(tmp_size), sizeof(tmp_size)); - - std::vector new_poly; - - // for every triangle.. - for (unsigned int i = 0; i < tmp_size * 3; i += 3) - { - new_poly.clear(); - - // ..get the 3 indices and save them - for (int j = 0; j < 3; j++) - { - std::uint32_t tmp_value; - m_fsMesh.read(F2V(tmp_value), sizeof(std::uint32_t)); - new_poly.push_back(tmp_value); - } - - new_segment->polyIndices.push_back(new_poly); - } - } - } - - dataDestination->segmList.push_back(new_segment); -} - -void MshFile::readVertex(Segment * dataDestination, std::streampos position) -{ - std::uint32_t tmp_size; - m_fsMesh.seekg(position); - m_fsMesh.read(F2V(tmp_size), sizeof(tmp_size)); - - dataDestination->vertex = new float[tmp_size * 3]; - - for (unsigned int i = 0; i < tmp_size * 3; i++) - m_fsMesh.read(F2V(dataDestination->vertex[i]), sizeof(float)); -} - -void MshFile::readUV(Segment * dataDestination, std::streampos position) -{ - std::uint32_t tmp_size; - m_fsMesh.seekg(position); - m_fsMesh.read(F2V(tmp_size), sizeof(tmp_size)); - - dataDestination->uv = new float[tmp_size * 2]; - - for (unsigned int i = 0; i < tmp_size * 2; i++) - m_fsMesh.read(F2V(dataDestination->uv[i]), sizeof(float)); -} diff --git a/MeshViewerQt/Source/OpenGlViewer.cpp b/MeshViewerQt/Source/OpenGlViewer.cpp deleted file mode 100644 index ba14af0..0000000 --- a/MeshViewerQt/Source/OpenGlViewer.cpp +++ /dev/null @@ -1,372 +0,0 @@ -#include "..\Header\OpenGlViewer.h" -#include -#include -#include - - -///////////////////////////////////////////////////////////////////////// -// Defined values - -//opengl -#define DEFAULT_MAJOR_VERSION 4 -#define DEFAULT_MINOR_VERSION 5 -#define DEAFAULT_BACKGROUND 0.5000f, 0.8000f, 1.0000f, 0.0000f - -//piplines -#define VERTEX_INDEX_XYZ 0 -#define VERTEX_INDEX_UV 1 - -#define VERTEX_COMPONENTS_XYZ 3 -#define VERTEX_COMPONENTS_UV 2 - -#define VERTEX_SIZE_XYZ (sizeof(float) * VERTEX_COMPONENTS_XYZ) -#define VERTEX_SIZE_UV (sizeof(float) * VERTEX_COMPONENTS_UV) - -#define VERTEX_OFFSET_XYZ 0 -#define VERTEX_OFFSET_UV (VERTEX_SIZE_XYZ) - - -///////////////////////////////////////////////////////////////////////// -// public constructor/destructor - -OpenGlViewer::OpenGlViewer(QWidget *parent) - : QOpenGLWidget(parent) -{ - QSurfaceFormat format; - format.setRenderableType(QSurfaceFormat::OpenGL); - format.setSamples(4); - format.setProfile(QSurfaceFormat::CoreProfile); - format.setVersion(DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION); - setFormat(format); - - //TODO: mouse, move, key, drag/drop, scroll, resize -} - -OpenGlViewer::~OpenGlViewer() -{ - glDeleteTextures(1, &m_oglTexture); - glDeleteBuffers(1, &m_vertexBuffer); - m_vertexArray.destroy(); - delete m_program; - - deleteData(); -} - - -///////////////////////////////////////////////////////////////////////// -// private functions - -void OpenGlViewer::initializeGL() -{ - initializeOpenGLFunctions(); - printContextInformation(); - - // set Background - glClearColor(DEAFAULT_BACKGROUND); - - //TODO: z-order? - - // draw vertices only from one side - glEnable(GL_CULL_FACE); - - // Create texture - glGenTextures(1, &m_oglTexture); - glBindTexture(GL_TEXTURE_2D, m_oglTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - - // Create Shader - m_program = new QOpenGLShaderProgram(); - m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert"); - m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/simple.frag"); - m_program->link(); - m_program->bind(); - - // get Uniform location - //TODO: faster to give everything to shader and calculate there? - m_uniformMVP = m_program->uniformLocation("MVP"); - - // Create Vertex Buffer - glGenBuffers(1, &m_vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); - - // Create Vertex Array Object - m_vertexArray.create(); - m_vertexArray.bind(); - m_program->enableAttributeArray(0); - m_program->enableAttributeArray(1); - m_program->setAttributeBuffer(VERTEX_INDEX_XYZ, GL_FLOAT, VERTEX_OFFSET_XYZ, VERTEX_COMPONENTS_XYZ, sizeof(Vertex)); - m_program->setAttributeBuffer(VERTEX_INDEX_UV, GL_FLOAT, VERTEX_OFFSET_UV, VERTEX_COMPONENTS_UV, sizeof(Vertex)); - - // unbind everything - m_vertexArray.release(); - glBindBuffer(GL_ARRAY_BUFFER, 0); - m_program->release(); - -} - -void OpenGlViewer::paintGL() -{ - //TODO: paint here - glClear(GL_COLOR_BUFFER_BIT); - - m_program->bind(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_oglTexture); - m_program->setUniformValue("textureSampler", 0); - - - if (m_vModels != nullptr) - { - int tmp_offset(0); - - for (unsigned int modelIndex = 0; modelIndex < m_vModels->size(); modelIndex++) - { - // skip null, bones, shadowMesh, hidden things - if (m_vModels->at(modelIndex)->type == null || - m_vModels->at(modelIndex)->type == bone || - m_vModels->at(modelIndex)->type == shadowMesh || - m_vModels->at(modelIndex)->renderFlags == 1) - continue; - - 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; - - glTexImage2D( - GL_TEXTURE_2D, - 0, - m_vTextures->at(tmp_textureIndex)->alpha ? GL_RGBA : GL_RGB, - m_vTextures->at(tmp_textureIndex)->width, - m_vTextures->at(tmp_textureIndex)->height, - 0, - m_vTextures->at(tmp_textureIndex)->alpha ? GL_BGRA : GL_BGR, - GL_UNSIGNED_BYTE, - m_vTextures->at(tmp_textureIndex)->data->data() - ); - - glGenerateMipmap(GL_TEXTURE_2D); - - // give the MVP to the shader - m_program->setUniformValue(m_uniformMVP, getMVPMatrix(modelIndex)); - - // calculate the number of vertex - unsigned int tmp_vertexCount(0); - for (auto&it : segmentIterator->polyIndices) - tmp_vertexCount += (it.size() - 2) * 3; - - glDrawArrays(GL_TRIANGLES, tmp_offset, tmp_vertexCount); - - // increase the offset - tmp_offset += tmp_vertexCount; - } - } - } - - m_program->release(); - - this->frameSwapped(); -} - -void OpenGlViewer::printContextInformation() -{ - QString glType; - QString glVersion; - QString glProfile; - - glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL"; - glVersion = reinterpret_cast(glGetString(GL_VERSION)); - -#define CASE(c) case QSurfaceFormat::c: glProfile = #c; break - switch (format().profile()) - { - CASE(NoProfile); - CASE(CoreProfile); - CASE(CompatibilityProfile); - } -#undef CASE - - 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 -{ - 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 != nullptr) - { - while (!m_vModels->empty()) - { - // remove the last Model - Model* modelVectorElement = m_vModels->back(); - m_vModels->pop_back(); - - while (!modelVectorElement->segmList.empty()) - { - // remove the last Segment - Segment* segmentVectorElement = modelVectorElement->segmList.back(); - modelVectorElement->segmList.pop_back(); - - // delete data from Segment - delete[] segmentVectorElement->uv; - delete[] segmentVectorElement->vertex; - - while (!segmentVectorElement->polyIndices.empty()) - { - // clear the poly vector and remove it from the list - segmentVectorElement->polyIndices.back().clear(); - segmentVectorElement->polyIndices.pop_back(); - } - - // delete the actual Segment - delete segmentVectorElement; - } - - // delete the actual Model - delete modelVectorElement; - } - - // delete the Model's Vector - delete m_vModels; - } - - if (m_vTextures != nullptr) - { - while (!m_vTextures->empty()) - { - // remove the last texture - TextureData* cursor = m_vTextures->back(); - m_vTextures->pop_back(); - - cursor->data->clear(); - delete cursor->data; - - //delete image - delete cursor; - } - // delete the Textrue's Vector - delete m_vTextures; - } -} - - -///////////////////////////////////////////////////////////////////////// -// public functions - -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; - } - } - } - } - - glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); - glBufferData( - GL_ARRAY_BUFFER, - sizeof(Vertex) * tmp_bufferData.size(), - tmp_bufferData.data(), - GL_STATIC_DRAW - ); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - tmp_bufferData.clear(); -} diff --git a/MeshViewerQt/Source/Texture.cpp b/MeshViewerQt/Source/Texture.cpp deleted file mode 100644 index 9ed6ff3..0000000 --- a/MeshViewerQt/Source/Texture.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "Texture.h" -#include - -TextureTGA::TextureTGA(const char * filePath) -{ - // open the file - std::fstream fsPicture(filePath, std::ios::in | std::ios::binary); - - if (!fsPicture.is_open()) - throw std::invalid_argument(std::string("file not found: ") += filePath); - - // read in the header - std::uint8_t ui8x18Header[19] = { 0 }; - fsPicture.read(reinterpret_cast(&ui8x18Header), sizeof(ui8x18Header)-1); - - //get variables - vui8Pixels = new std::vector; - bool bCompressed; - std::uint32_t ui32IDLength; - std::uint32_t ui32PicType; - std::uint32_t ui32PaletteLength; - std::uint32_t ui32Size; - - // extract all information from header - ui32IDLength = ui8x18Header[0]; - ui32PicType = ui8x18Header[2]; - ui32PaletteLength = ui8x18Header[6] * 0x100 + ui8x18Header[5]; - ui32Width = ui8x18Header[13] * 0x100 + ui8x18Header[12]; - ui32Height = ui8x18Header[15] * 0x100 + ui8x18Header[14]; - ui32BpP = ui8x18Header[16]; - - // calculate some more information - ui32Size = ui32Width * ui32Height * ui32BpP/8; - bCompressed = ui32PicType == 9 || ui32PicType == 10; - vui8Pixels->resize(ui32Size); - - // jump to the data block - fsPicture.seekg(ui32IDLength + ui32PaletteLength, std::ios_base::cur); - - // If not compressed 24 or 32 bit - if (ui32PicType == 2 && (ui32BpP == 24 || ui32BpP == 32)) - { - fsPicture.read(reinterpret_cast(vui8Pixels->data()), ui32Size); - } - // else if compressed 24 or 32 bit - else if (ui32PicType == 10 && (ui32BpP == 24 || ui32BpP == 32)) // compressed - { - std::uint8_t tempChunkHeader; - std::uint8_t tempData[5]; - unsigned int tempByteIndex = 0; - - do { - fsPicture.read(reinterpret_cast(&tempChunkHeader), sizeof(tempChunkHeader)); - - if (tempChunkHeader >> 7) // repeat count - { - // just use the first 7 bits - tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1); - - fsPicture.read(reinterpret_cast(&tempData), ui32BpP/8); - - for (int i = 0; i <= tempChunkHeader; i++) - { - vui8Pixels->at(tempByteIndex++) = tempData[0]; - vui8Pixels->at(tempByteIndex++) = tempData[1]; - vui8Pixels->at(tempByteIndex++) = tempData[2]; - if(ui32BpP == 32) vui8Pixels->at(tempByteIndex++) = tempData[3]; - } - } - else // data count - { - // just use the first 7 bits - tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1); - - for (int i = 0; i <= tempChunkHeader; i++) - { - fsPicture.read(reinterpret_cast(&tempData), ui32BpP/8); - - vui8Pixels->at(tempByteIndex++) = tempData[0]; - vui8Pixels->at(tempByteIndex++) = tempData[1]; - vui8Pixels->at(tempByteIndex++) = tempData[2]; - if (ui32BpP == 32) vui8Pixels->at(tempByteIndex++) = tempData[3]; - } - } - } while (tempByteIndex < ui32Size); - } - // not useable format - else - { - fsPicture.close(); - throw std::invalid_argument("Invaild File Format! Required 24 or 31 Bit Image."); - } - - fsPicture.close(); -} - -TextureTGA::~TextureTGA() -{ -} - -std::vector* TextureTGA::getData() const -{ - return vui8Pixels; -} - -bool TextureTGA::hasAlpha() const -{ - return ui32BpP == 32; -} - -std::uint32_t TextureTGA::getWidth() const -{ - return ui32Width; -} - -std::uint32_t TextureTGA::getHeight() const -{ - return ui32Height; -} diff --git a/MeshViewerQt/main.cpp b/MeshViewerQt/main.cpp deleted file mode 100644 index d412abb..0000000 --- a/MeshViewerQt/main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Header\MainWindow.h" -#include - - -int startGUI(int argc, char* argv[]) -{ - QApplication a(argc, argv); - MainWindow w; - w.show(); - return a.exec(); -} - -int main(int argc, char *argv[]) -{ - int exitstatus = startGUI(argc, argv); - - return exitstatus; -} diff --git a/QtMeshViewer/Form Files/SettingsWindow.ui b/QtMeshViewer/Form Files/SettingsWindow.ui index b8ae54f..75d8917 100644 --- a/QtMeshViewer/Form Files/SettingsWindow.ui +++ b/QtMeshViewer/Form Files/SettingsWindow.ui @@ -21,7 +21,7 @@ - + false @@ -31,8 +31,11 @@ 16777215 - - 5 + + QAbstractSpinBox::NoButtons + + + 255 @@ -86,7 +89,7 @@ - + false @@ -96,8 +99,11 @@ 16777215 - - 5 + + QAbstractSpinBox::NoButtons + + + 255 @@ -123,28 +129,34 @@ - + 30 16777215 - - 204 + + QAbstractSpinBox::NoButtons + + + 255 - + 30 16777215 - - 255 + + QAbstractSpinBox::NoButtons + + + 255 @@ -162,7 +174,7 @@ - + true @@ -172,8 +184,11 @@ 16777215 - - 127 + + QAbstractSpinBox::NoButtons + + + 255 @@ -225,7 +240,7 @@ - + false @@ -235,8 +250,11 @@ 16777215 - - 5 + + QAbstractSpinBox::NoButtons + + + 255 @@ -314,28 +332,34 @@ - + 30 16777215 - - 255 + + QAbstractSpinBox::NoButtons + + + 255 - + 30 16777215 - - 255 + + QAbstractSpinBox::NoButtons + + + 255 @@ -350,15 +374,18 @@ - + 30 16777215 - - 255 + + QAbstractSpinBox::NoButtons + + + 255 @@ -443,7 +470,7 @@ - false + true diff --git a/QtMeshViewer/Header/SettingsWindow.h b/QtMeshViewer/Header/SettingsWindow.h index 24c3581..30cd517 100644 --- a/QtMeshViewer/Header/SettingsWindow.h +++ b/QtMeshViewer/Header/SettingsWindow.h @@ -8,12 +8,14 @@ class SettingsWindow : public QWidget Q_OBJECT public: - SettingsWindow(QWidget * parent = Q_NULLPTR); + SettingsWindow(QVector3D bgOffColor, QVector3D bgOnColor, QVector3D lightColor, bool autoColor, double ambCoef, double attFac, int lightType, QWidget * parent = Q_NULLPTR); ~SettingsWindow(); private: Ui::SettingsWindow* ui; + void setupConnections(); + private slots: void autoColorToggled(); void radioToggled(); diff --git a/QtMeshViewer/Source/OglViewerWidget.cpp b/QtMeshViewer/Source/OglViewerWidget.cpp index 9040908..b81da8a 100644 --- a/QtMeshViewer/Source/OglViewerWidget.cpp +++ b/QtMeshViewer/Source/OglViewerWidget.cpp @@ -15,12 +15,13 @@ OglViewerWidget::OglViewerWidget(QWidget *parent) : QOpenGLWidget(parent) , m_dataEngine(0) - , m_settings(new SettingsWindow(this)) { setFocus(); m_translation.setZ(DEFAULT_Z_DISTANCE); setAcceptDrops(true); + m_settings = new SettingsWindow(m_backgroundColorOff.toVector3D() * 255, m_backgroundColorOn.toVector3D() * 255, m_light.intensities * 255, true, m_light.ambientCoefficient, m_light.attenuationFactor, 1, this); + connect(m_settings, &SettingsWindow::updateBGColorOff, this, &OglViewerWidget::setBGColorOff); connect(m_settings, &SettingsWindow::updateBGColorOn, this, &OglViewerWidget::setBGColorOn); connect(m_settings, &SettingsWindow::updateLightColor, this, &OglViewerWidget::setLightColor); diff --git a/QtMeshViewer/Source/SettingsWindow.cpp b/QtMeshViewer/Source/SettingsWindow.cpp index 183c027..de0c0b7 100644 --- a/QtMeshViewer/Source/SettingsWindow.cpp +++ b/QtMeshViewer/Source/SettingsWindow.cpp @@ -1,7 +1,7 @@ #include "..\Header\SettingsWindow.h" #include -SettingsWindow::SettingsWindow(QWidget * parent) +SettingsWindow::SettingsWindow(QVector3D bgOffColor, QVector3D bgOnColor, QVector3D lightColor, bool autoColor, double ambCoef, double attFac, int lightType, QWidget * parent) : QWidget(parent) , ui(new Ui::SettingsWindow) { @@ -9,43 +9,74 @@ SettingsWindow::SettingsWindow(QWidget * parent) setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint); + setupConnections(); + + // set default values + ui->lightOff_R_SB->setValue((int)bgOffColor[0]); + ui->lightOff_G_SB->setValue((int)bgOffColor[1]); + ui->lightOff_B_SB->setValue((int)bgOffColor[2]); + + ui->lightOn_R_SB->setValue((int)bgOnColor[0]); + ui->lightOn_G_SB->setValue((int)bgOnColor[1]); + ui->lightOn_B_SB->setValue((int)bgOnColor[2]); + + ui->light_R_SB->setValue((int)lightColor[0]); + ui->light_G_SB->setValue((int)lightColor[1]); + ui->light_B_SB->setValue((int)lightColor[2]); + + ui->ambCoef->setValue(ambCoef); + ui->attFac->setValue(attFac); + + ui->checkAutoColor->setChecked(autoColor); + if (lightType == 1) + ui->radioDirectLight->setChecked(true); + +} + +SettingsWindow::~SettingsWindow() +{ + delete ui; +} + +void SettingsWindow::setupConnections() +{ // light off - connect(ui->lightOff_R_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOff_R_S->setValue(value.toInt());}); - connect(ui->lightOff_R_S, &QSlider::valueChanged, [this](const int& value){ui->lightOff_R_LE->setText(QString::number(value));}); + connect(ui->lightOff_R_SB, SIGNAL(valueChanged(int)), ui->lightOff_R_S, SLOT(setValue(int))); + connect(ui->lightOff_R_S, SIGNAL(valueChanged(int)), ui->lightOff_R_SB, SLOT(setValue(int))); connect(ui->lightOff_R_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged); - connect(ui->lightOff_G_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOff_G_S->setValue(value.toInt());}); - connect(ui->lightOff_G_S, &QSlider::valueChanged, [this](const int& value){ui->lightOff_G_LE->setText(QString::number(value));}); + connect(ui->lightOff_G_SB, SIGNAL(valueChanged(int)), ui->lightOff_G_S, SLOT(setValue(int))); + connect(ui->lightOff_G_S, SIGNAL(valueChanged(int)), ui->lightOff_G_SB, SLOT(setValue(int))); connect(ui->lightOff_G_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged); - connect(ui->lightOff_B_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOff_B_S->setValue(value.toInt());}); - connect(ui->lightOff_B_S, &QSlider::valueChanged, [this](const int& value){ui->lightOff_B_LE->setText(QString::number(value));}); + connect(ui->lightOff_B_SB, SIGNAL(valueChanged(int)), ui->lightOff_B_S, SLOT(setValue(int))); + connect(ui->lightOff_B_S, SIGNAL(valueChanged(int)), ui->lightOff_B_SB, SLOT(setValue(int))); connect(ui->lightOff_B_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged); // light on - connect(ui->lightOn_R_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOn_R_S->setValue(value.toInt());}); - connect(ui->lightOn_R_S, &QSlider::valueChanged, [this](const int& value){ui->lightOn_R_LE->setText(QString::number(value));}); + connect(ui->lightOn_R_SB, SIGNAL(valueChanged(int)), ui->lightOn_R_S, SLOT(setValue(int))); + connect(ui->lightOn_R_S, SIGNAL(valueChanged(int)), ui->lightOn_R_SB, SLOT(setValue(int))); connect(ui->lightOn_R_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged); - connect(ui->lightOn_G_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOn_G_S->setValue(value.toInt());}); - connect(ui->lightOn_G_S, &QSlider::valueChanged, [this](const int& value){ui->lightOn_G_LE->setText(QString::number(value));}); + connect(ui->lightOn_G_SB, SIGNAL(valueChanged(int)), ui->lightOn_G_S, SLOT(setValue(int))); + connect(ui->lightOn_G_S, SIGNAL(valueChanged(int)), ui->lightOn_G_SB, SLOT(setValue(int))); connect(ui->lightOn_G_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged); - connect(ui->lightOn_B_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOn_B_S->setValue(value.toInt());}); - connect(ui->lightOn_B_S, &QSlider::valueChanged, [this](const int& value){ui->lightOn_B_LE->setText(QString::number(value));}); + connect(ui->lightOn_B_SB, SIGNAL(valueChanged(int)), ui->lightOn_B_S, SLOT(setValue(int))); + connect(ui->lightOn_B_S, SIGNAL(valueChanged(int)), ui->lightOn_B_SB, SLOT(setValue(int))); connect(ui->lightOn_B_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged); // light - connect(ui->light_R_LE, &QLineEdit::textChanged, [this](const QString& value){ui->light_R_S->setValue(value.toInt());}); - connect(ui->light_R_S, &QSlider::valueChanged, [this](const int& value){ui->light_R_LE->setText(QString::number(value)); if(ui->checkAutoColor->isChecked()) ui->lightOn_R_S->setValue((int)(value / 50));}); + connect(ui->light_R_SB, SIGNAL(valueChanged(int)), ui->light_R_S, SLOT(setValue(int))); + connect(ui->light_R_S, SIGNAL(valueChanged(int)), ui->light_R_SB, SLOT(setValue(int))); connect(ui->light_R_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged); - connect(ui->light_G_LE, &QLineEdit::textChanged, [this](const QString& value){ui->light_G_S->setValue(value.toInt());}); - connect(ui->light_G_S, &QSlider::valueChanged, [this](const int& value){ui->light_G_LE->setText(QString::number(value)); if(ui->checkAutoColor->isChecked()) ui->lightOn_G_S->setValue((int)(value / 50));}); + connect(ui->light_G_SB, SIGNAL(valueChanged(int)), ui->light_G_S, SLOT(setValue(int))); + connect(ui->light_G_S, SIGNAL(valueChanged(int)), ui->light_G_SB, SLOT(setValue(int))); connect(ui->light_G_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged); - connect(ui->light_B_LE, &QLineEdit::textChanged, [this](const QString& value){ui->light_B_S->setValue(value.toInt());}); - connect(ui->light_B_S, &QSlider::valueChanged, [this](const int& value){ui->light_B_LE->setText(QString::number(value)); if(ui->checkAutoColor->isChecked()) ui->lightOn_B_S->setValue((int)(value / 50));}); + connect(ui->light_B_SB, SIGNAL(valueChanged(int)), ui->light_B_S, SLOT(setValue(int))); + connect(ui->light_B_S, SIGNAL(valueChanged(int)), ui->light_B_SB, SLOT(setValue(int))); connect(ui->light_B_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged); @@ -55,10 +86,6 @@ SettingsWindow::SettingsWindow(QWidget * parent) connect(ui->attFac, static_cast(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAttFac(value); }); } -SettingsWindow::~SettingsWindow() -{ - delete ui; -} //////////////////////////////////////////////////////////////////////////////// // connection slots @@ -67,43 +94,38 @@ void SettingsWindow::autoColorToggled() { if (!ui->checkAutoColor->isChecked()) { - ui->lightOn_R_LE->setEnabled(true); + ui->lightOn_R_SB->setEnabled(true); ui->lightOn_R_S->setEnabled(true); - ui->lightOn_G_LE->setEnabled(true); + ui->lightOn_G_SB->setEnabled(true); ui->lightOn_G_S->setEnabled(true); - ui->lightOn_B_LE->setEnabled(true); + ui->lightOn_B_SB->setEnabled(true); ui->lightOn_B_S->setEnabled(true); } else { - ui->lightOn_R_LE->setEnabled(false); + ui->lightOn_R_SB->setEnabled(false); ui->lightOn_R_S->setEnabled(false); - ui->lightOn_G_LE->setEnabled(false); + ui->lightOn_G_SB->setEnabled(false); ui->lightOn_G_S->setEnabled(false); - ui->lightOn_B_LE->setEnabled(false); + ui->lightOn_B_SB->setEnabled(false); ui->lightOn_B_S->setEnabled(false); - ui->lightOn_R_LE->setText(QString::number((int)(ui->light_R_S->value() / 50))); ui->lightOn_R_S->setValue((int)(ui->light_R_S->value() / 50)); - ui->lightOn_G_LE->setText(QString::number((int)(ui->light_G_S->value() / 50))); ui->lightOn_G_S->setValue((int)(ui->light_G_S->value() / 50)); - ui->lightOn_B_LE->setText(QString::number((int)(ui->light_B_S->value() / 50))); ui->lightOn_B_S->setValue((int)(ui->light_B_S->value() / 50)); } } void SettingsWindow::radioToggled() { - if(ui->radioDirectLight->isChecked()) + if (ui->radioDirectLight->isChecked()) { ui->attFac->setValue(0.0); ui->attFac->setEnabled(false); - ui->ambCoef->setEnabled(false); } else { ui->attFac->setEnabled(true); - ui->ambCoef->setEnabled(true); } } @@ -120,5 +142,12 @@ void SettingsWindow::backgroundColorOnChanged() void SettingsWindow::lightColorChanged() { emit updateLightColor(QVector3D(ui->light_R_S->value(), ui->light_G_S->value(), ui->light_B_S->value())); + + if (ui->checkAutoColor->isChecked()) + { + ui->lightOn_R_S->setValue((int)(ui->light_R_S->value() / 50)); + ui->lightOn_G_S->setValue((int)(ui->light_G_S->value() / 50)); + ui->lightOn_B_S->setValue((int)(ui->light_B_S->value() / 50)); + } }