diff --git a/MeshViewerQt/Form Files/MainWindow.ui b/MeshViewerQt/Form Files/MainWindow.ui
new file mode 100644
index 0000000..739421a
--- /dev/null
+++ b/MeshViewerQt/Form Files/MainWindow.ui
@@ -0,0 +1,35 @@
+
+
+ MainWindowClass
+
+
+
+ 0
+ 0
+ 600
+ 400
+
+
+
+ MainWindow
+
+
+
+
+ false
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 0000000..ca011cd
--- /dev/null
+++ b/MeshViewerQt/Header/MainWindow.h
@@ -0,0 +1,32 @@
+#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
new file mode 100644
index 0000000..4fdf953
--- /dev/null
+++ b/MeshViewerQt/Header/MshFile.h
@@ -0,0 +1,34 @@
+#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
new file mode 100644
index 0000000..8f91453
--- /dev/null
+++ b/MeshViewerQt/Header/OpenGlViewer.h
@@ -0,0 +1,67 @@
+#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
new file mode 100644
index 0000000..cd56653
--- /dev/null
+++ b/MeshViewerQt/Header/Texture.h
@@ -0,0 +1,22 @@
+#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
new file mode 100644
index 0000000..cbf9149
--- /dev/null
+++ b/MeshViewerQt/Header/defines.h
@@ -0,0 +1,8 @@
+#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
new file mode 100644
index 0000000..3d2b578
--- /dev/null
+++ b/MeshViewerQt/Resources/MainWindow.qrc
@@ -0,0 +1,11 @@
+
+
+ icon.ico
+
+
+ simple.frag
+ simple.vert
+ TextureShader.frag
+ TextureShader.vert
+
+
diff --git a/MeshViewerQt/Resources/TextureShader.frag b/MeshViewerQt/Resources/TextureShader.frag
new file mode 100644
index 0000000..3c9924a
--- /dev/null
+++ b/MeshViewerQt/Resources/TextureShader.frag
@@ -0,0 +1,12 @@
+#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
new file mode 100644
index 0000000..b8865eb
--- /dev/null
+++ b/MeshViewerQt/Resources/TextureShader.vert
@@ -0,0 +1,17 @@
+#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
new file mode 100644
index 0000000..3a2186f
Binary files /dev/null and b/MeshViewerQt/Resources/icon.ico differ
diff --git a/MeshViewerQt/Resources/simple.frag b/MeshViewerQt/Resources/simple.frag
new file mode 100644
index 0000000..9844eff
--- /dev/null
+++ b/MeshViewerQt/Resources/simple.frag
@@ -0,0 +1,8 @@
+#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
new file mode 100644
index 0000000..fad59f5
--- /dev/null
+++ b/MeshViewerQt/Resources/simple.vert
@@ -0,0 +1,10 @@
+#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
new file mode 100644
index 0000000..2148647
--- /dev/null
+++ b/MeshViewerQt/Source/MainWindow.cpp
@@ -0,0 +1,151 @@
+#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
new file mode 100644
index 0000000..a683cc5
--- /dev/null
+++ b/MeshViewerQt/Source/MshFile.cpp
@@ -0,0 +1,569 @@
+#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
new file mode 100644
index 0000000..ba14af0
--- /dev/null
+++ b/MeshViewerQt/Source/OpenGlViewer.cpp
@@ -0,0 +1,372 @@
+#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
new file mode 100644
index 0000000..9ed6ff3
--- /dev/null
+++ b/MeshViewerQt/Source/Texture.cpp
@@ -0,0 +1,119 @@
+#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
new file mode 100644
index 0000000..d412abb
--- /dev/null
+++ b/MeshViewerQt/main.cpp
@@ -0,0 +1,18 @@
+#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;
+}