Compare commits

...

40 Commits

Author SHA1 Message Date
itdominator 64d5584698 Update 'README.md' 2021-04-26 21:07:42 +00:00
Anakin 7e87b14fe1 made all path relative now 2017-04-30 15:05:21 +02:00
Anakin da0b7e3c5f new release version,
Features:
- fixed overexposed specular bug,
- most settings are saved after each session
Bugs:
-nothing known
2017-02-08 14:32:48 +01:00
Anakin fa75e17d58 most settings are saved and restored 2017-02-08 14:29:22 +01:00
Anakin 49585945c3 fixed too high specular,
updated preview.jpg
2017-02-06 16:53:27 +01:00
Anakin 67657061b6 new release version,
Features:
- normal map support,
- added specular support for cloth,
- "glow" support,
Bugs:
- normal mapping looks a bit drizzly depending on the angle of view
2017-02-06 14:59:46 +01:00
Anakin 06d403d546 support normal map now,
support "glow" now,
update preview.jpg
2017-02-06 14:53:05 +01:00
Anakin 541a975624 added preview imange,
passed data to shader,
need to process data in shader
2017-02-05 20:10:05 +01:00
Anakin 30f1a1e627 passing poylNormal, tangent, bitangent to shader 2017-02-05 16:57:12 +01:00
Anakin cdf19911f6 calculate polygon normal, tangent, and bitangent,
next step, use them for calculation
2017-02-05 16:39:37 +01:00
Anakin 4c40d140a9 cloth now has specular 2017-02-05 15:25:59 +01:00
Anakin f47e1cc76a new release version,
Features:
- extreme performance improvement when loading files,
- new camera controls (free, orbital, move),
- using ogl 4.5 again since 2.0 causes problems on some pc,
Bugs:
- nothing known
2017-02-05 12:38:32 +01:00
Anakin 2d335474bf fixed camera control,
removed test exe
2017-02-05 12:34:24 +01:00
Anakin a07d8acbec update gui for camera mods 2017-02-04 17:42:44 +01:00
Anakin 800a6a50f8 doesn't work for ggctuk since i use ogl 2.0 instead of 4.5
trying to figure out the problem
2017-02-04 15:57:15 +01:00
Anakin 94a2fa59ec added MoveCamera but isn't working well
updated about text,
2017-02-04 15:48:10 +01:00
Anakin 648b805daf forget to save file 2017-02-03 15:55:04 +01:00
Anakin 92245be302 finished OrbitCamera 2017-02-03 15:54:45 +01:00
Anakin 333eca25eb use class for camera handling,
orbit does not work. Need to figure out why
2017-02-02 18:01:08 +01:00
Anakin b17ab3f8e9 fixed out of file check order 2017-02-02 15:26:40 +01:00
Anakin ff08ee7cea error handling when out of file 2017-02-02 15:10:48 +01:00
Anakin 8346e5916d changed everything from std to qt 2017-02-02 14:44:48 +01:00
Anakin 5372838420 further performance improvement 2017-02-02 11:14:16 +01:00
Anakin a14229aa71 further improvement on tga import 2017-02-01 17:53:42 +01:00
Anakin 1c5631a5e0 improve image load performance,
can be improved more, but scanline has wrong results
2017-02-01 17:41:29 +01:00
Anakin bc5bfc62bc fixed a bug 2017-02-01 16:34:43 +01:00
Anakin 4cb070c8c5 removed files from repo that are not needed in the release folder 2017-01-30 17:24:21 +01:00
Anakin 2d9c103c01 new release version,
Features:
- Headlight option,
- zoom speed now adjust in settings window, not via +/-,
- cullface can be activated in the settings,
- text in FileInfoWindow can be marked and copied,
- alpha channel now always used,
- fixed compatibility problems,
- code and performance improvements,
Bugs:
- nothing known
2017-01-30 17:10:41 +01:00
Anakin 37e9b86daa fixed bug that sometimes alpha channel was not read in,
code improvement = performance,
2017-01-30 16:54:35 +01:00
Anakin 4342260e6d improved performance using my own tga load function always instead of QImage
improved Profiler
2017-01-30 16:00:14 +01:00
Anakin d1c68e8ba6 added Profiler to analyses the time used by code lines 2017-01-30 12:01:45 +01:00
Anakin 9c16aa32f1 headlight,
bug fixes,
code improvement,
2017-01-30 11:31:37 +01:00
Anakin fbb51563c9 fixed backface culling bug,
todo: connect headligh
2017-01-30 00:02:32 +01:00
Anakin 538453c1db added headlight option to settings,
added cullface option to settings,
zoom speed now adjust at settings,
bugs:
cullface does not work anymore,
todo:
connect headlight
2017-01-29 23:47:14 +01:00
Anakin 7b739ab892 use OutputDevice to set fileinfo,
use new connect function,
2017-01-29 15:19:20 +01:00
Anakin 98302664ca add OuputDevice as singleton to manage output to statusbar, 2017-01-29 11:35:43 +01:00
Anakin 96b7d6f736 text in FileInfoWindow can be marked and copied,
code cleaning
2017-01-28 16:54:36 +01:00
Anakin 121f5c47f1 fixed some warnings 2017-01-26 19:44:12 +01:00
Anakin fe374cb8f6 made fshader.glsl compatible with older versions 2017-01-26 18:25:24 +01:00
Anakin fb49d8685a switch from QLineEdit to QSpinBox,
init SettingsWindow with default values from OglViewerWidget,
removed old qt project
2017-01-26 18:17:54 +01:00
88 changed files with 2243 additions and 2631 deletions

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindowClass</class>
<widget class="QMainWindow" name="MainWindowClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QToolBar" name="mainToolBar">
<property name="movable">
<bool>false</bool>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="../Resources/MainWindow.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1,72 +0,0 @@
#pragma once
#include <fstream>
#include <vector>
#include <QMatrix4x4>
//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<std::vector<std::uint32_t>> 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<Segment*> segmList;
};
class FileInterface
{
public:
FileInterface(const char* path)
: m_vModels(new std::vector<Model*>)
{
//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<Model*>* m_vModels;
std::fstream m_fsMesh;
std::vector<std::string> m_vTextureNames;
BoundingBox m_sceneBbox;
virtual void import() = 0;
public:
virtual std::vector<Model*>* getModels() const { return m_vModels; };
virtual std::vector<std::string> getTextureNames() const { return m_vTextureNames; };
virtual BoundingBox getBoundingBox() const { return m_sceneBbox; };
};

View File

@ -1,32 +0,0 @@
#pragma once
#include <QtWidgets/QMainWindow>
#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;
};

View File

@ -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<ChunkHeader*> &destination, std::streampos start, const std::uint32_t length);
void analyseMsh2Chunks(std::list<ChunkHeader*> &chunkList);
void analyseMatdChunks(std::list<ChunkHeader*> &chunkList);
void analyseModlChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseGeomChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseSegmChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseClthChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void readVertex(Segment* dataDestination, std::streampos position);
void readUV(Segment* dataDestination, std::streampos position);
};

View File

@ -1,67 +0,0 @@
#pragma once
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOPenGLVertexArrayObject>
#include <QOpenGlShaderProgram>
#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<std::uint8_t>* 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<Model*>* m_vModels = nullptr;
std::vector<TextureData*>* 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<Model*>* models, std::vector<TextureData*>* textures, BoundingBox bbox);
};

View File

@ -1,22 +0,0 @@
#pragma once
#include <vector>
class TextureTGA
{
public:
TextureTGA(const char* filePath);
~TextureTGA();
private:
std::vector<std::uint8_t>* vui8Pixels;
std::uint32_t ui32BpP;
std::uint32_t ui32Width;
std::uint32_t ui32Height;
public:
std::vector<std::uint8_t>* getData() const;
bool hasAlpha() const;
std::uint32_t getWidth() const;
std::uint32_t getHeight() const;
};

View File

@ -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"

View File

@ -1,11 +0,0 @@
<RCC>
<qresource prefix="/MainWindow">
<file>icon.ico</file>
</qresource>
<qresource prefix="/shaders">
<file>simple.frag</file>
<file>simple.vert</file>
<file>TextureShader.frag</file>
<file>TextureShader.vert</file>
</qresource>
</RCC>

View File

@ -1,12 +0,0 @@
#version 330
// Input
in vec2 UV;
// Output
out vec4 color;
void main()
{
color = {255,0,0};//texture(textureSampler, UV).rgb;
}

View File

@ -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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

View File

@ -1,8 +0,0 @@
#version 330
in vec4 vColor;
out vec4 fColor;
void main()
{
fColor = vColor;
}

View File

@ -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);
}

View File

@ -1,151 +0,0 @@
#include "..\Header\MainWindow.h"
#include "..\Header\OpenGlViewer.h"
#include "..\Header\MshFile.h"
#include "..\Header\defines.h"
#include <QKeyEvent>
#include <QMessageBox>
#include <QFileDialog>
/////////////////////////////////////////////////////////////////////////
// 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<Model*>* tmp_models = nullptr;
std::vector<TextureData*>* tmp_textures = new std::vector<TextureData*>;
std::vector<std::string> 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<std::uint8_t>({ 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<std::uint8_t>({ 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<OpenGlViewer*>(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);
}

View File

@ -1,569 +0,0 @@
#include "..\Header\MshFile.h"
#include <iostream>
// helper function to save data from file to any variable type
#define F2V(variableName) reinterpret_cast<char*>(&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<ChunkHeader*> 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<ChunkHeader*> 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<ChunkHeader*>& 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<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// scene information
if (!strcmp("SINF", it->name))
{
// get SINF subchunks
std::list<ChunkHeader*> 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<ChunkHeader*> 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<ChunkHeader*> 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<ChunkHeader*> 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<ChunkHeader*>& 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<ChunkHeader*>& 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<ChunkHeader*> 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<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// segment
if (!strcmp("SEGM", it->name))
{
// get all SEGM subchunks
std::list<ChunkHeader*> 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<ChunkHeader*> 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<ChunkHeader*>& 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<char*>(&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<uint32_t> 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<ChunkHeader*>& 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<uint32_t> 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));
}

View File

@ -1,372 +0,0 @@
#include "..\Header\OpenGlViewer.h"
#include <cmath>
#include <iostream>
#include <QMessageBox>
/////////////////////////////////////////////////////////////////////////
// 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<const char*>(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<Model*>* models, std::vector<TextureData*>* 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<Vertex> 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();
}

View File

@ -1,119 +0,0 @@
#include "Texture.h"
#include <fstream>
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<char*>(&ui8x18Header), sizeof(ui8x18Header)-1);
//get variables
vui8Pixels = new std::vector<std::uint8_t>;
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<char*>(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<char*>(&tempChunkHeader), sizeof(tempChunkHeader));
if (tempChunkHeader >> 7) // repeat count
{
// just use the first 7 bits
tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1);
fsPicture.read(reinterpret_cast<char*>(&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<char*>(&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<std::uint8_t>* 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;
}

View File

@ -1,18 +0,0 @@
#include "Header\MainWindow.h"
#include <QtWidgets/QApplication>
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;
}

View File

@ -47,6 +47,9 @@ Triangles: -</string>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>

View File

@ -19,7 +19,9 @@
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
<property name="allowedAreas">
<set>Qt::LeftToolBarArea|Qt::RightToolBarArea|Qt::TopToolBarArea</set>
@ -32,6 +34,72 @@
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QDockWidget" name="dockWidget">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="features">
<set>QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetFloatable</set>
</property>
<property name="allowedAreas">
<set>Qt::RightDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>Asset library</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -7,21 +7,21 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<height>358</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBackground">
<property name="title">
<string>Background</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="5">
<widget class="QLineEdit" name="lightOn_G_LE">
<widget class="QSpinBox" name="lightOn_G_SB">
<property name="enabled">
<bool>false</bool>
</property>
@ -31,8 +31,11 @@
<height>16777215</height>
</size>
</property>
<property name="text">
<string>5</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -86,7 +89,7 @@
</widget>
</item>
<item row="4" column="8">
<widget class="QLineEdit" name="lightOn_B_LE">
<widget class="QSpinBox" name="lightOn_B_SB">
<property name="enabled">
<bool>false</bool>
</property>
@ -96,8 +99,11 @@
<height>16777215</height>
</size>
</property>
<property name="text">
<string>5</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -123,28 +129,34 @@
</widget>
</item>
<item row="2" column="5">
<widget class="QLineEdit" name="lightOff_G_LE">
<widget class="QSpinBox" name="lightOff_G_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>204</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="2" column="8">
<widget class="QLineEdit" name="lightOff_B_LE">
<widget class="QSpinBox" name="lightOff_B_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>255</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -162,7 +174,7 @@
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="lightOff_R_LE">
<widget class="QSpinBox" name="lightOff_R_SB">
<property name="enabled">
<bool>true</bool>
</property>
@ -172,8 +184,11 @@
<height>16777215</height>
</size>
</property>
<property name="text">
<string>127</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -225,7 +240,7 @@
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="lightOn_R_LE">
<widget class="QSpinBox" name="lightOn_R_SB">
<property name="enabled">
<bool>false</bool>
</property>
@ -235,8 +250,11 @@
<height>16777215</height>
</size>
</property>
<property name="text">
<string>5</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -263,46 +281,28 @@
</property>
</widget>
</item>
<item row="5" column="5">
<spacer name="verticalSpacerBackground">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QGroupBox" name="groupLight">
<property name="title">
<string>Light</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="labelAmbCoeff">
<property name="text">
<string>Ambientcoefficient:</string>
<item row="1" column="1">
<widget class="QSpinBox" name="light_R_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QLabel" name="labelAttFac">
<property name="text">
<string>Attenuationfactor:</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>B:</string>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -313,59 +313,49 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QLabel" name="labelAttFac">
<property name="text">
<string>Attenuationfactor:</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLineEdit" name="light_G_LE">
<widget class="QSpinBox" name="light_G_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>255</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="light_R_LE">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<item row="1" column="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>255</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QRadioButton" name="radioDirectLight">
<property name="text">
<string>Directional light</string>
</property>
<property name="checked">
<bool>true</bool>
<string>B:</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QLineEdit" name="light_B_LE">
<widget class="QSpinBox" name="light_B_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>255</string>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>R:</string>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
@ -395,31 +385,22 @@
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QSlider" name="light_G_S">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>255</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>R:</string>
</property>
</widget>
</item>
<item row="4" column="4">
<spacer name="verticalSpacerLight">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="0" column="0" colspan="4">
<widget class="QRadioButton" name="radioDirectLight">
<property name="text">
<string>Directional light</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<property name="checked">
<bool>true</bool>
</property>
</spacer>
</widget>
</item>
<item row="3" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="attFac">
@ -443,7 +424,7 @@
<item row="2" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="ambCoef">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
@ -465,7 +446,34 @@
</property>
</widget>
</item>
<item row="0" column="4" colspan="4">
<item row="1" column="5">
<widget class="QSlider" name="light_G_S">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>255</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="labelAmbCoeff">
<property name="text">
<string>Ambientcoefficient:</string>
</property>
</widget>
</item>
<item row="0" column="7" colspan="2">
<widget class="QCheckBox" name="checkHeadlight">
<property name="text">
<string>Headlight</string>
</property>
</widget>
</item>
<item row="0" column="4" colspan="3">
<widget class="QRadioButton" name="radioPointLight">
<property name="text">
<string>Point light</string>
@ -475,6 +483,71 @@
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupGeneral">
<property name="title">
<string>General</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelZoomSpeed">
<property name="text">
<string>Zoom speed:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="spinZSpeed">
<property name="suffix">
<string>%</string>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QCheckBox" name="checkBackfaceCulling">
<property name="text">
<string>Backface Culling</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>

View File

@ -0,0 +1,26 @@
#pragma once
#include <QMatrix4x4>
class CameraInterface
{
public:
explicit CameraInterface() {};
virtual ~CameraInterface() {};
// attributes
protected:
QMatrix4x4 m_matrix;
double m_zSpeed = 1.0;
// functions
public:
virtual void setZoomSpeed(int percent) { m_zSpeed = (double) percent / 100; };
virtual void rotateAction(QVector2D diff) = 0;
virtual void moveAction(QVector2D diff) = 0;
virtual void wheelAction(double value) = 0;
virtual void resetView() { m_matrix = QMatrix4x4(); };
virtual void recalculateMatrix() = 0;
virtual QMatrix4x4 getMatrix() { recalculateMatrix(); return m_matrix; };
};

View File

@ -1,6 +1,5 @@
#pragma once
#include <QWidget>
#include <QString>
#include "ui_FileInfoWindow.h"
class FileInfoWindow : public QWidget
@ -8,13 +7,21 @@ class FileInfoWindow : public QWidget
Q_OBJECT
public:
FileInfoWindow(QWidget *parent = Q_NULLPTR);
~FileInfoWindow();
FileInfoWindow(QWidget *parent = Q_NULLPTR)
: QWidget(parent)
, ui(new Ui::FileInfoWindow)
{
ui->setupUi(this);
setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
ui->scrollArea->widget()->setStyleSheet("background-color: #ffffff");
};
~FileInfoWindow() { delete ui; };
private:
Ui::FileInfoWindow* ui;
public:
void setBasicText(QString text);
void setDetailText(QString text);
void setBasicText(QString text) { ui->basic->setText(text); };
void setDetailText(QString text) { ui->detail->setText(text); };
};

View File

@ -1,17 +1,11 @@
#pragma once
#include <fstream>
#include <QOpenGlTexture>
#include <QFile>
#include <QVector>
#include <QVector2D>
#include <QVector3D>
#include <QMatrix4x4>
#include <QQuaternion>
#include <QOpenGLFunctions>
#include <QOpenGlTexture>
#include <QObject>
#include <QOpenGLTexture>
#include <QRegExp>
#include <..\Header\MainWindow.h>
struct BoundingBox {
QQuaternion rotation;
@ -24,20 +18,23 @@ struct VertexData
QVector3D position;
QVector2D texCoord;
QVector3D vertexNormal;
QVector3D polygonNormal;
QVector3D tangent;
QVector3D bitangent;
};
struct Segment {
std::uint32_t textureIndex = 0;
quint32 textureIndex = 0;
QVector<VertexData> vertices;
QVector<GLuint> indices;
};
struct Model {
std::string name = "";
std::string parent = "";
QString name = "";
QString parent = "";
QMatrix4x4 m4x4Translation;
QQuaternion quadRotation;
std::vector<Segment*> segmList;
QVector<Segment*> segmList;
};
struct Material {
@ -48,36 +45,30 @@ struct Material {
QString tx3d;
QOpenGLTexture* texture0 = Q_NULLPTR;
QOpenGLTexture* texture1 = Q_NULLPTR;
QVector4D specularColor = { 1.0, 1.0, 1.0, 1.0 };
QVector4D specularColor = { 0.1f, 0.1f, 0.1f, 1.0 };
QVector4D diffuseColor = { 1.0, 0.0, 0.0, 1.0 };
QVector4D ambientColor = { 1.0, 1.0, 1.0, 1.0 };
float shininess = 80;
float shininess = 1;
bool flags[8] = { false };
bool transparent = false;
std::uint8_t rendertype = 0;
std::uint8_t dataValues[2] = { 0 };
quint8 rendertype = 0;
quint8 dataValues[2] = { 0 };
};
class FileInterface : public QObject
class FileInterface
{
Q_OBJECT
public:
explicit FileInterface(QString path, QObject *parent)
: QObject(parent)
, m_models(new QVector<Model*>)
explicit FileInterface(QString path)
: m_models(new QVector<Model*>)
, m_materials(new QVector<Material>)
{
//open file
m_file.open(path.toStdString().c_str(), std::ios::in | std::ios::binary);
m_file.setFileName(path);
if (!m_file.is_open())
if (!m_file.open(QIODevice::ReadOnly))
throw std::invalid_argument(std::string("ERROR: file not found: ") += path.toStdString());
MainWindow* tmp = dynamic_cast<MainWindow*>(parent->parent()->parent());
if(tmp != NULL)
connect(this, SIGNAL(sendMessage(QString, int)), tmp, SLOT(printMessage(QString, int)));
m_filepath = path.left(path.lastIndexOf(QRegExp("/|\\\\")));
};
@ -106,7 +97,7 @@ public:
protected:
QVector<Model*>* m_models;
std::fstream m_file;
QFile m_file;
QVector<Material>* m_materials;
BoundingBox m_sceneBbox;
QString m_filepath;
@ -142,6 +133,4 @@ public:
return defMaterial;
};
signals:
void sendMessage(QString msg, int severity);
};

View File

@ -0,0 +1,23 @@
#pragma once
#include "CameraInterface.h"
class FreeCamera : public CameraInterface
{
public:
explicit FreeCamera();
virtual ~FreeCamera();
// attributes
private:
QVector3D m_translation;
QQuaternion m_rotation;
// functions
public:
virtual void rotateAction(QVector2D diff) Q_DECL_OVERRIDE;
virtual void moveAction(QVector2D diff) Q_DECL_OVERRIDE;
virtual void wheelAction(double value) Q_DECL_OVERRIDE;
virtual void recalculateMatrix() Q_DECL_OVERRIDE;
virtual void resetView() Q_DECL_OVERRIDE;
};

View File

@ -1,11 +1,11 @@
#pragma once
#include "..\Header\FileInterface.h"
#include <QObject>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QVector>
#include "FileInterface.h"
struct DrawInformation {
unsigned int offset;
@ -22,24 +22,27 @@ public:
GeometryEngine(QObject *parent = Q_NULLPTR);
virtual ~GeometryEngine();
// attributes
private:
QOpenGLBuffer m_arrayBuf;
QOpenGLBuffer m_indexBuf;
QVector<Material>* m_materials = Q_NULLPTR;
QVector<DrawInformation> m_drawList;
BoundingBox m_boundings;
Material* m_defaultMaterial;
BoundingBox m_boundings;
QVector<DrawInformation> m_drawList;
// functions
private:
void clearData();
void setupPipeline(QOpenGLShaderProgram * program);
public slots:
public:
void drawGeometry(QOpenGLShaderProgram *program);
void loadFile(QString filePath);
void drawGeometry(QOpenGLShaderProgram *program, bool wireframe);
// signals
signals:
void requestResetView();
void sendMessage(QString message, int severity);
void requestUpdate();
void sendFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle);
};

View File

@ -1,12 +1,11 @@
#pragma once
#include <QtWidgets/QMainWindow>
#include <qwidget.h>
#include <QByteArray>
#include <QStringList>
#include <QLabel>
#include <QWidget>
#include "ui_MainWindow.h"
#include "..\Header\FileInfoWindow.h"
#include "FileInfoWindow.h"
#include <QByteArray>
#include <QLabel>
struct Material;
@ -18,27 +17,34 @@ public:
MainWindow(QWidget *parent = Q_NULLPTR);
~MainWindow();
// attributes
private:
Ui::MainWindowClass* ui;
int m_curSeverity;
void setupWidgets();
QByteArray m_fileInfo;
QLabel* m_output;
int m_curSeverity;
FileInfoWindow* m_infoWindow;
// functions
private:
void setupWidgets();
void getAssetLibrary();
void searchMeshFiles(QString path);
void openFile();
void aboutFile();
void aboutTool();
void takeScreenShot();
void aboutTool();
protected:
virtual void resizeEvent(QResizeEvent * e) Q_DECL_OVERRIDE;
// slots
public slots:
void printMessage(QString message, int severity);
void setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle);
// signals
signals:
void loadFile(QString);
};

View File

@ -0,0 +1,26 @@
#pragma once
#include "CameraInterface.h"
class MoveCamera : public CameraInterface
{
public:
explicit MoveCamera();
virtual ~MoveCamera();
// attributes
private:
QVector3D m_position;
double m_phi;
double m_theta;
int m_forwardSpeed;
int m_sidewardSpeed;
// functions
public:
virtual void rotateAction(QVector2D diff) Q_DECL_OVERRIDE;
virtual void moveAction(QVector2D diff) Q_DECL_OVERRIDE;
virtual void wheelAction(double value) Q_DECL_OVERRIDE;
virtual void recalculateMatrix() Q_DECL_OVERRIDE;
virtual void resetView() Q_DECL_OVERRIDE;
};

View File

@ -1,11 +1,11 @@
#pragma once
#include "..\Header\FileInterface.h"
#include <QList>
struct ChunkHeader {
char name[5];
std::uint32_t size;
std::streampos position;
QString name;
quint32 size;
qint64 position;
};
enum ModelTyp {
@ -20,7 +20,7 @@ enum ModelTyp {
class MshFile : public FileInterface
{
public:
explicit MshFile(QString path, QObject *parent = Q_NULLPTR);
explicit MshFile(QString path);
virtual ~MshFile();
private:
@ -29,22 +29,22 @@ private:
virtual void import() Q_DECL_OVERRIDE Q_DECL_FINAL;
void loadChunks(std::list<ChunkHeader*> &destination, std::streampos start, const std::uint32_t length);
void loadChunks(QList<ChunkHeader*> &destination, qint64 start, const quint32 length);
void analyseMsh2Chunks(std::list<ChunkHeader*> &chunkList);
void analyseMsh2Chunks(QList<ChunkHeader*> &chunkList);
void analyseMatdChunks(std::list<ChunkHeader*> &chunkList);
void analyseMatdChunks(QList<ChunkHeader*> &chunkList);
void analyseModlChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseGeomChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseSegmChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseClthChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList);
void analyseModlChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void analyseGeomChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void analyseSegmChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void analyseClthChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void readVertex(Segment* dataDestination, std::streampos position);
void readUV(Segment* dataDestination, std::streampos position);
void readVertex(Segment* dataDestination, qint64 position);
void readUV(Segment* dataDestination, qint64 position);
void loadTexture(QOpenGLTexture*& destination, QString filepath, QString& filename);
QMatrix4x4 getParentMatrix(std::string parent) const;
QQuaternion getParentRotation(std::string parent) const;
QMatrix4x4 getParentMatrix(QString parent) const;
QQuaternion getParentRotation(QString parent) const;
};

View File

@ -1,14 +1,11 @@
#pragma once
#include "geometryengine.h"
#include "..\Header\SettingsWindow.h"
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QMatrix4x4>
#include <QQuaternion>
#include <QVector2D>
#include <QBasicTimer>
#include <QOpenGLShaderProgram>
#include <QMatrix4x4>
#include "GeometryEngine.h"
#include "SettingsWindow.h"
#include "CameraInterface.h"
class GeometryEngine;
@ -21,79 +18,82 @@ public:
explicit OglViewerWidget(QWidget *parent = 0);
~OglViewerWidget();
signals:
void loadFile(QString);
// attributes
private:
QOpenGLShaderProgram m_program;
GeometryEngine *m_dataEngine;
QVector4D m_backgroundColorOn;
QVector4D m_backgroundColorOff;
bool m_wireframe;
bool m_lightOn;
bool m_backfaceCulling;
struct {
QVector4D position;
QVector3D intensities;
float attenuationFactor;
float ambientCoefficient;
bool headlight;
} m_light;
struct {
bool left = false;
bool right = false;
QVector2D position;
} m_mouse;
struct {
bool x = true;
bool y = true;
bool z = true;
} m_rotDirections;
struct {
QVector4D position = { 1,1,1,0 };
QVector3D intensities = { 1.0,1.0,1.0 };
float attenuationFactor = 0.0f;
float ambientCoefficient = 0.005f;
} m_light;
QMatrix4x4 m_projection;
CameraInterface* m_camera;
SettingsWindow* m_settings;
QVector4D m_backgroundColorOn = {0.02f, 0.02f, 0.02f, 1.0f};
QVector4D m_backgroundColorOff = { 0.5f, 0.8f, 1.0f, 1.0f };
QOpenGLShaderProgram m_program;
GeometryEngine *m_dataEngine;
QMatrix4x4 m_projection;
QVector3D m_translation;
QQuaternion m_rotation;
bool m_wireframe = false;
bool m_lightOn = false;
double m_zSpeed = 1.0;
// functions
private:
void setDefaultValues();
void initShaders();
void resetView();
void updateLightPosition();
protected:
void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void wheelEvent(QWheelEvent *e) Q_DECL_OVERRIDE;
void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE;
void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE;
void initializeGL() Q_DECL_OVERRIDE;
void resizeGL(int w, int h) Q_DECL_OVERRIDE;
void paintGL() Q_DECL_OVERRIDE;
private:
void initShaders();
void setConnections();
void updateLightPosition();
void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void wheelEvent(QWheelEvent *e) Q_DECL_OVERRIDE;
void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE;
void keyReleaseEvent(QKeyEvent *e) Q_DECL_OVERRIDE;
private slots:
void resetView();
void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE;
// slots
public slots:
void changeDirection(int direction);
void loadFile(QString name);
void useFreeCamera();
void useOrbitCamera();
void useMoveCamera();
void toggleWireframe();
void toggleLight();
void showSettings();
void setBGColorOff(QVector3D value);
void setBGColorOn(QVector3D value);
void setLightColor(QVector3D value);
void setAttFac(double value);
void setAmbCoef(double value);
void setHeadlight(bool value);
void setBackfaceCulling(bool value);
// signals
signals:
void sendMessage(QString message, int severity);
void lightChanged(bool value);
};

View File

@ -0,0 +1,24 @@
#pragma once
#include "CameraInterface.h"
class OrbitCamera : public CameraInterface
{
public:
explicit OrbitCamera();
virtual ~OrbitCamera();
// attributes
private:
double m_phi;
double m_theta;
double m_roh;
// functions
public:
virtual void rotateAction(QVector2D diff) Q_DECL_OVERRIDE;
virtual void moveAction(QVector2D diff) Q_DECL_OVERRIDE;
virtual void wheelAction(double value) Q_DECL_OVERRIDE;
virtual void recalculateMatrix() Q_DECL_OVERRIDE;
virtual void resetView() Q_DECL_OVERRIDE;
};

View File

@ -0,0 +1,32 @@
#pragma once
#include <QObject>
struct Material;
class OutputDevice : public QObject
{
Q_OBJECT
private:
OutputDevice(QObject *parent = Q_NULLPTR) : QObject(parent) {};
public:
OutputDevice(OutputDevice const&) = delete;
void operator=(OutputDevice const&) = delete;
~OutputDevice() {};
static OutputDevice* getInstance(QObject *parent = Q_NULLPTR) {
static OutputDevice* instance = new OutputDevice(parent);
return instance;
};
void print(QString message, int severity) { emit sendMessage(message, severity); };
void setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle) {
emit sendFileInfo(name, materials, vertices, triangle);
};
signals:
void sendMessage(QString message, int severity);
void sendFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle);
};

View File

@ -0,0 +1,38 @@
#pragma once
#ifdef _DEBUG
#include <QElapsedTimer.h>
#include <QString>
#include <iostream>
#define TIC(val) Profiler::getInstance().startTimer(val);
#define TOC(val) Profiler::getInstance().takeTime(val);
class Profiler
{
private:
Profiler() { timer.start(); };
QElapsedTimer timer;
public:
~Profiler() {};
static Profiler& getInstance() {
static Profiler instance;
return instance;
}
void startTimer(QString position = "") {
std::cout << "from: " << position.toStdString() << std::endl;
timer.restart();
};
void takeTime(QString position = "") {
std::cout << "to: "<< position.toStdString() << " time elapsed: " << timer.elapsed() << std::endl;
};
};
#else
#define TIC(val)
#define TOC(val)
#endif

View File

@ -0,0 +1,72 @@
#pragma once
#include <QObject>
#include <QFile>
#include <QVector3D>
#include <QVector4D>
class SettingsManager : public QObject
{
Q_OBJECT
private:
SettingsManager(QObject *parent = Q_NULLPTR);
public:
SettingsManager(SettingsManager const&) = delete;
void operator=(SettingsManager const&) = delete;
~SettingsManager();
static SettingsManager* getInstance(QObject *parent = Q_NULLPTR);
// attributes
private:
QFile file;
QVector3D m_bgColorOn = { 5, 5, 5 };
QVector3D m_bgColorOff = { 128, 204, 255 };
bool m_bfCulling = false;
bool m_light = false;
int m_lightType = 1; // 1 = direct, 2 = point
QVector3D m_lightColor = { 255,255,255 };
float m_attenuation = 0.0f;
float m_ambient = 0.005f;
bool m_headlight = false;
bool m_autoColor = true;
// functions
private:
void readFromFile();
void writeToFile();
public:
QVector3D getBgColorOn() const;
QVector3D getBgColorOff() const;
bool isBfCulling() const;
bool isLight() const;
int getLightType() const;
QVector3D getLightColor() const;
float getAttenuation() const;
float getAmbient() const;
bool isHeadlight() const;
bool isAutoColor() const;
// slots
public:
void setBgColorOn(QVector3D value);
void setBgColorOff(QVector3D value);
void setBfCulling(bool value);
void setLight(bool value);
void setLightType(int value);
void setLightColor(QVector3D value);
void setAttenuation(double value);
void setAmbient(double value);
void setHeadlight(bool value);
void setAutoColor(int value);
};

View File

@ -3,6 +3,7 @@
#include "ui_SettingsWindow.h"
#include <QVector3D>
class SettingsWindow : public QWidget
{
Q_OBJECT
@ -14,6 +15,8 @@ public:
private:
Ui::SettingsWindow* ui;
void setupConnections();
private slots:
void autoColorToggled();
void radioToggled();
@ -27,4 +30,9 @@ signals:
void updateLightColor(QVector3D value);
void updateAttFac(double value);
void updateAmbCoef(double value);
void sendHeadlight(bool value);
void sendBackfaceCulling(bool value);
void sendZommSpeed(int percent);
void changeLightType(int value);
};

View File

@ -1,39 +1,38 @@
#pragma once
#include <fstream>
#include "OutputDevice.h"
#include <QImage>
#include <QColor>
#include <QVector>
#include <QFile>
#include <iostream>
QImage loadTga(QString filePath, bool &success)
{
QImage img;
if (!img.load(filePath))
success = true;
// open the file
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly))
{
success = false;
}
else
{
// open the file
std::fstream fsPicture(filePath.toStdString().c_str(), std::ios::in | std::ios::binary);
if (!fsPicture.is_open())
{
img = QImage(1, 1, QImage::Format_RGB32);
img.fill(Qt::red);
success = false;
return img;
}
// read in the header
std::uint8_t ui8x18Header[19] = { 0 };
fsPicture.read(reinterpret_cast<char*>(&ui8x18Header), sizeof(ui8x18Header) - 1);
quint8 ui8x18Header[19] = { 0 };
file.read(reinterpret_cast<char*>(&ui8x18Header), sizeof(ui8x18Header) - 1);
//get variables
std::uint32_t ui32BpP;
std::uint32_t ui32Width;
std::uint32_t ui32Height;
std::uint32_t ui32IDLength;
std::uint32_t ui32PicType;
std::uint32_t ui32PaletteLength;
std::uint32_t ui32Size;
quint32 ui32BpP;
quint32 ui32Width;
quint32 ui32Height;
quint32 ui32IDLength;
quint32 ui32PicType;
quint32 ui32PaletteLength;
quint32 ui32Size;
// extract all information from header
ui32IDLength = ui8x18Header[0];
@ -47,57 +46,49 @@ QImage loadTga(QString filePath, bool &success)
ui32Size = ui32Width * ui32Height * ui32BpP / 8;
// jump to the data block
fsPicture.seekg(ui32IDLength + ui32PaletteLength, std::ios_base::cur);
img = QImage(ui32Width, ui32Height, ui32BpP == 32? QImage::Format_RGBA8888 : QImage::Format_RGB888);
file.seek(ui32IDLength + ui32PaletteLength + 18);
// uncompressed
if (ui32PicType == 2 && (ui32BpP == 24 || ui32BpP == 32))
{
std::vector<std::uint8_t> vui8Pixels;
vui8Pixels.resize(ui32Size);
fsPicture.read(reinterpret_cast<char*>(vui8Pixels.data()), ui32Size);
img = QImage(ui32Width, ui32Height, ui32BpP == 32 ? QImage::Format_RGBA8888 : QImage::Format_RGB888);
int lineWidth = ui32Width * ui32BpP / 8;
for (unsigned int y = 0; y < ui32Height; y++)
{
for (unsigned int x = 0; x < ui32Width; x++)
{
int valr = vui8Pixels.at(y * ui32Width * ui32BpP / 8 + x * ui32BpP / 8 + 2);
int valg = vui8Pixels.at(y * ui32Width * ui32BpP / 8 + x * ui32BpP / 8 + 1);
int valb = vui8Pixels.at(y * ui32Width * ui32BpP / 8 + x * ui32BpP / 8);
for (int i = ui32Height - 1; i >= 0; --i)
file.read(reinterpret_cast<char*>(img.scanLine(i)), lineWidth);
QColor value(valr, valg, valb);
img.setPixelColor(x, ui32Width - 1 - y, value);
}
}
}
// 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];
OutputDevice::getInstance()->print("compressed tga is not supported by SWBF", 1);
img = QImage(ui32Width, ui32Height, QImage::Format_RGBA8888);
quint8 tempChunkHeader;
quint8 tempData[5];
unsigned int tmp_pixelIndex = 0;
do {
fsPicture.read(reinterpret_cast<char*>(&tempChunkHeader), sizeof(tempChunkHeader));
file.read(reinterpret_cast<char*>(&tempChunkHeader), sizeof(tempChunkHeader));
if (tempChunkHeader >> 7) // repeat count
{
// just use the first 7 bits
tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1);
tempChunkHeader = (quint8(tempChunkHeader << 1) >> 1);
fsPicture.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
file.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
for (int i = 0; i <= tempChunkHeader; i++)
{
QColor color;
if (ui32BpP == 32)
color.setRgba(qRgba(tempData[2], tempData[1], tempData[0], tempData[3]));
color.setRgba(qRgba(tempData[0], tempData[1], tempData[2], tempData[3]));
else
color.setRgb(qRgb(tempData[2], tempData[1], tempData[0]));
color.setRgba(qRgba(tempData[0], tempData[1], tempData[2], 255));
img.setPixelColor(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color);
img.setPixel(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color.rgba());
tmp_pixelIndex++;
}
}
@ -108,16 +99,16 @@ QImage loadTga(QString filePath, bool &success)
for (int i = 0; i <= tempChunkHeader; i++)
{
fsPicture.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
file.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
QColor color;
if (ui32BpP == 32)
color.setRgba(qRgba(tempData[2], tempData[1], tempData[0], tempData[3]));
color.setRgba(qRgba(tempData[0], tempData[1], tempData[2], tempData[3]));
else
color.setRgb(qRgb(tempData[2], tempData[1], tempData[0]));
color.setRgba(qRgba(tempData[0], tempData[1], tempData[2], 255));
img.setPixelColor(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color);
img.setPixel(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color.rgba());
tmp_pixelIndex++;
}
}
@ -126,15 +117,12 @@ QImage loadTga(QString filePath, bool &success)
// not useable format
else
{
fsPicture.close();
img = QImage(1, 1, QImage::Format_RGB32);
img.fill(Qt::red);
success = false;
return img;
}
fsPicture.close();
}
success = true;
return img;
if (file.isOpen())
file.close();
return qMove(img).rgbSwapped();
}

View File

@ -15,17 +15,14 @@
<file>info.png</file>
<file>about.png</file>
<file>open.png</file>
<file>X.png</file>
<file>Y.png</file>
<file>Z.png</file>
<file>screenshot.png</file>
<file>wireframe.png</file>
<file>light_off.png</file>
<file>light_on.png</file>
<file>solid.png</file>
<file>X_disabled.png</file>
<file>Y_disabled.png</file>
<file>Z_disabled.png</file>
<file>settings.png</file>
<file>freeCamera.png</file>
<file>orbitalCamera.png</file>
<file>walkCamera.png</file>
</qresource>
</RCC>

View File

@ -1,3 +1,9 @@
QLabel#output {
color : white;
min-width: 400px;
min-height: 50px;
}
QToolButton {
image: url(:/images/toolbar/placeholder.png);
border-style: none;
@ -31,28 +37,16 @@ QToolButton#screenshot {
image: url(:/images/toolbar/screenshot.png);
}
QToolButton#x {
image: url(:/images/toolbar/X_disabled.png);
QToolButton#freeCamera {
image: url(:/images/toolbar/freeCamera.png);
}
QToolButton#x:checked {
image: url(:/images/toolbar/X.png);
QToolButton#orbitalCamera {
image: url(:/images/toolbar/orbitalCamera.png);
}
QToolButton#y {
image: url(:/images/toolbar/Y_disabled.png);
}
QToolButton#y:checked {
image: url(:/images/toolbar/Y.png);
}
QToolButton#z {
image: url(:/images/toolbar/Z_disabled.png);
}
QToolButton#z:checked {
image: url(:/images/toolbar/Z.png);
QToolButton#walkCamera {
image: url(:/images/toolbar/walkCamera.png);
}
QToolButton#wireframe {

View File

@ -4,11 +4,23 @@ source code: https://git.rwth-aachen.de/carstenf/OpenGL/tree/master/QtMeshViewer
===============================================================
Controll:
Free Camera: static view position and you rotate and move the object
left mouse - rotate
right mouse - move
scroll - zoom
Orbit Camera: static object and you move around it like a satalite
left mouse - rotate
scroll - zoom
Move Camera: static object and you can walk through the scene
w/s - forward/backward
a/d - left/right
left mouse - look around
General:
space - reset view
+/- - adjust zoom speed
L - set light to current position
esc - close

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

View File

@ -4,16 +4,22 @@ precision mediump int;
precision mediump float;
#endif
uniform mat3 n_matrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
uniform sampler2D texture;
uniform float materialShininess;
uniform vec3 materialSpecularColor;
uniform sampler2D tx0;
uniform sampler2D tx1;
uniform bool b_transparent;
uniform bool b_specular;
uniform bool b_light;
uniform struct Material {
float shininess;
vec3 specularColor;
bool isTransparent;
bool hasSpecularmap;
bool hasNormalmap;
bool isGlow;
} material;
uniform bool useLight;
uniform struct Light {
vec4 position;
@ -25,64 +31,96 @@ uniform struct Light {
varying vec2 v_surfaceUV;
varying vec3 v_surfacePosition;
varying vec3 v_surfaceNormal;
varying vec3 v_polyNorm;
varying vec3 v_polyTan;
varying vec3 v_polyBiTan;
void main()
{
if(b_light)
if(useLight && !material.isGlow)
{
// some values
vec3 normalWorld = normalize(n_matrix * v_surfaceNormal);
vec4 surfaceColor = vec4(texture2D(texture, v_surfaceUV));
// get the color and undo gamma correction
vec4 surfaceColor = vec4(texture2D(tx0, v_surfaceUV));
surfaceColor.rgb = pow(surfaceColor.rgb, vec3(2.2));
vec3 surfaceToLight;
float attenuation;
// directional light
if(light.position.w == 0)
{
surfaceToLight = normalize(light.position.xyz);
}
// point light
else
{
surfaceToLight = normalize(light.position.xyz - v_surfacePosition);
}
float distanceToLight = length(light.position.xyz - v_surfacePosition);
attenuation = 1.0 / (1.0 + light.attenuationFactor * pow(distanceToLight, 2));
// attenutation depending on the distance to the light
float distanceToLight = length(light.position.xyz - v_surfacePosition);
float attenuation = 1.0 / (1.0 + light.attenuationFactor * pow(distanceToLight, 2));
// normal vector
vec3 normal = normalize(normalMatrix * v_surfaceNormal);
// direction from surface to light depending on the light type
vec3 surfaceToLight;
if(light.position.w == 0.0) // directional light
surfaceToLight = normalize(light.position.xyz);
else // point light
surfaceToLight = normalize(light.position.xyz - v_surfacePosition);
// direction from surface to camera
vec3 surfaceToCamera = normalize(cameraPosition - v_surfacePosition);
// ambient
// adjust the values if material has normal map
if(material.hasNormalmap)
{
vec3 surfaceTangent = normalize(normalMatrix * v_polyTan);
vec3 surfaceBitangent = normalize(normalMatrix * -v_polyBiTan);
vec3 surfaceNormal = normalize(normalMatrix * v_surfaceNormal);
mat3 tbn = transpose(mat3(surfaceTangent, surfaceBitangent, surfaceNormal));
normal = texture2D(tx1, v_surfaceUV).rgb;
normal = normalize(normal * 2.0 -1.0);
surfaceToLight = normalize(tbn * surfaceToLight);
surfaceToCamera = normalize(tbn * surfaceToCamera);
}
/////////////////////////////////////////////////////////////////////////////////////
// ambient component
vec3 ambient = light.ambientCoefficient * surfaceColor.rgb * light.intensities;
// diffuse
float diffuseCoefficient = max(0.0, dot(normalWorld, surfaceToLight));
/////////////////////////////////////////////////////////////////////////////////////
// diffuse component
float diffuseCoefficient = max(0.0, dot(normal, surfaceToLight));
vec3 diffuse = diffuseCoefficient * surfaceColor.rgb * light.intensities;
// specular
/////////////////////////////////////////////////////////////////////////////////////
// specular component
float specularCoefficient = 0.0;
if(diffuseCoefficient > 0.0)
specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normalWorld))), materialShininess);
if(b_specular)
materialSpecularColor = vec3(surfaceColor.a);
vec3 specular = specularCoefficient * materialSpecularColor * light.intensities;
specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normal))), material.shininess);
float specularWeight = 1;
if(material.hasSpecularmap)
specularWeight = surfaceColor.a;
vec3 specColor = specularWeight * 1/255 * material.specularColor;
// linear color before gamma correction)
vec3 specular = specularCoefficient * specColor * light.intensities;
/////////////////////////////////////////////////////////////////////////////////////
// linear color before gamma correction
vec3 linearColor = ambient + attenuation * (diffuse + specular);
// final color after gama correction
/////////////////////////////////////////////////////////////////////////////////////
// gama correction
vec3 gamma = vec3(1.0/2.2);
if(!b_transparent)
surfaceColor.a = 1.0f;
if(!material.isTransparent)
surfaceColor.a = 1.0;
gl_FragColor = vec4(pow(linearColor, gamma), surfaceColor.a);
}
// don't use light
else
{
vec4 surfaceColor = vec4(texture2D(texture, v_surfaceUV));
if(!b_transparent)
surfaceColor.a = 1.0f;
vec4 surfaceColor = vec4(texture2D(tx0, v_surfaceUV));
if(!material.isTransparent)
surfaceColor.a = 1.0;
gl_FragColor = surfaceColor;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

View File

@ -4,26 +4,35 @@ precision mediump int;
precision mediump float;
#endif
uniform mat4 vp_matrix;
uniform mat4 norm_matrix;
uniform mat4 m_matrix;
uniform mat4 viewProjection;
uniform mat4 normalizeModel;
uniform mat4 modelMatrix;
attribute vec4 a_position;
attribute vec2 a_texcoord;
attribute vec3 a_normal;
attribute vec3 a_polyNorm;
attribute vec3 a_polyTan;
attribute vec3 a_polyBiTan;
varying vec2 v_surfaceUV;
varying vec3 v_surfacePosition;
varying vec3 v_surfaceNormal;
varying vec3 v_polyNorm;
varying vec3 v_polyTan;
varying vec3 v_polyBiTan;
void main()
{
// Calculate vertex position in screen space
gl_Position = vp_matrix * norm_matrix * m_matrix * a_position;
gl_Position = viewProjection * normalizeModel * modelMatrix * a_position;
// Pass data to fragment shader
// Value will be automatically interpolated to fragments inside polygon faces
v_surfaceUV = a_texcoord;
v_surfacePosition = vec3(norm_matrix * m_matrix * a_position);
v_surfacePosition = vec3(normalizeModel * modelMatrix * a_position);
v_surfaceNormal = a_normal;
v_polyNorm = a_polyNorm;
v_polyTan = a_polyTan;
v_polyBiTan = a_polyBiTan;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

View File

@ -1,29 +0,0 @@
#include "..\Header\FileInfoWindow.h"
#include <QIcon>
FileInfoWindow::FileInfoWindow(QWidget *parent)
: QWidget(parent)
, ui(new Ui::FileInfoWindow)
{
ui->setupUi(this);
setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
ui->scrollArea->widget()->setStyleSheet("background-color: #ffffff");
}
FileInfoWindow::~FileInfoWindow()
{
delete ui;
}
void FileInfoWindow::setBasicText(QString text)
{
ui->basic->setText(text);
}
void FileInfoWindow::setDetailText(QString text)
{
ui->detail->setText(text);
}

View File

@ -0,0 +1,53 @@
#include "..\Header\FreeCamera.h"
#include <QVector2D>
#include <QVector3D>
#include <QQuaternion>
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
FreeCamera::FreeCamera()
{
resetView();
}
FreeCamera::~FreeCamera()
{
}
/////////////////////////////////////////////////////////////////////////
// functions
void FreeCamera::rotateAction(QVector2D diff)
{
m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(diff.y(), diff.x(), 0.0).normalized(), diff.length() * 0.5) * m_rotation;
}
void FreeCamera::moveAction(QVector2D diff)
{
m_translation += {(float)(diff.x() * 0.01), (float)(diff.y() * -0.01), 0.0};
}
void FreeCamera::wheelAction(double value)
{
m_translation += {0.0, 0.0, (float) (m_zSpeed * value / 240)};
}
void FreeCamera::recalculateMatrix()
{
m_matrix = QMatrix4x4();
m_matrix.translate(m_translation);
m_matrix.rotate(m_rotation);
}
void FreeCamera::resetView()
{
m_translation = { 0, 0, -4 };
m_rotation = QQuaternion();
CameraInterface::resetView();
}

View File

@ -2,20 +2,19 @@
#include "..\Header\MshFile.h"
#include "..\Header\OglViewerWidget.h"
#include "..\Header\MainWindow.h"
#include <cmath>
#include "..\Header\OutputDevice.h"
#include <QRegExp>
/////////////////////////////////////////////////////////////////////////
// public constructor/destructor
// constructor/destructor
GeometryEngine::GeometryEngine(QObject *parent)
: QObject(parent)
, m_indexBuf(QOpenGLBuffer::IndexBuffer)
, m_defaultMaterial(FileInterface::getDefaultMaterial())
{
initializeOpenGLFunctions();
m_defaultMaterial = FileInterface::getDefaultMaterial();
}
GeometryEngine::~GeometryEngine()
@ -27,7 +26,7 @@ GeometryEngine::~GeometryEngine()
/////////////////////////////////////////////////////////////////////////
// private functions
// functions
void GeometryEngine::clearData()
{
@ -52,9 +51,139 @@ void GeometryEngine::clearData()
m_drawList.clear();
}
void GeometryEngine::setupPipeline(QOpenGLShaderProgram *program)
{
// Offset for position
quintptr offset = 0;
/////////////////////////////////////////////////////////////////////////
// public slots
// Tell OpenGL programmable pipeline how to locate vertex position data
int vertexLocation = program->attributeLocation("a_position");
program->enableAttributeArray(vertexLocation);
program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
// Offset for texture coordinate
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
int texcoordLocation = program->attributeLocation("a_texcoord");
program->enableAttributeArray(texcoordLocation);
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
//Offset for vertexNormal
offset += sizeof(QVector2D);
// Tell OpenGL programmable pipeline how to locate vertex normal data
int vertNormLocation = program->attributeLocation("a_normal");
program->enableAttributeArray(vertNormLocation);
program->setAttributeBuffer(vertNormLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
//Offset for polygonNormal
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate polygon normal data
int polyNormLocation = program->attributeLocation("a_polyNorm");
program->enableAttributeArray(polyNormLocation);
program->setAttributeBuffer(polyNormLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
//Offset for polygonTangent
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate polygon tangent data
int polyTanLocation = program->attributeLocation("a_polyTan");
program->enableAttributeArray(polyTanLocation);
program->setAttributeBuffer(polyTanLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
//Offset for polygonBitangent
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate polygon bitangent data
int polyBiTanLocation = program->attributeLocation("a_polyBiTan");
program->enableAttributeArray(polyBiTanLocation);
program->setAttributeBuffer(polyBiTanLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
}
void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program)
{
if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated())
return;
// Setup
// Tell OpenGL which VBOs to use
m_arrayBuf.bind();
m_indexBuf.bind();
// Allways normalize by this
QMatrix4x4 normMatrix;
float maxExtent = std::max(std::max(m_boundings.extents[0], m_boundings.extents[1]), m_boundings.extents[2]);
normMatrix.scale(1 / maxExtent);
normMatrix.translate(-m_boundings.center[0], -m_boundings.center[1], -m_boundings.center[2]);
program->setUniformValue("normalizeModel", normMatrix);
// Allways use texture unit 0 and 1
program->setUniformValue("tx0", 0);
program->setUniformValue("tx1", 1);
//setup the pipeline
setupPipeline(program);
// Paint
for (auto& it : m_drawList)
{
bool tmp_transparent(false);
bool tmp_specular(false);
bool tmp_normalmap(false);
bool tmp_glow(false);
float shininess(0.0);
QVector3D specularColor;
// bind the correct texture
if (it.textureIndex < (unsigned)m_materials->size() && m_materials->at(it.textureIndex).texture0 != Q_NULLPTR)
{
m_materials->at(it.textureIndex).texture0->bind(0);
tmp_transparent = m_materials->at(it.textureIndex).transparent;
tmp_specular = m_materials->at(it.textureIndex).flags[7];
shininess = m_materials->at(it.textureIndex).shininess;
specularColor = m_materials->at(it.textureIndex).specularColor.toVector3D();
if (m_materials->at(it.textureIndex).rendertype == 27 || m_materials->at(it.textureIndex).rendertype == 28)
{
if (m_materials->at(it.textureIndex).texture1 != Q_NULLPTR)
{
tmp_normalmap = true;
m_materials->at(it.textureIndex).texture1->bind(1);
}
}
if (m_materials->at(it.textureIndex).flags[0] || m_materials->at(it.textureIndex).flags[1] || m_materials->at(it.textureIndex).rendertype == 1)
tmp_glow = true;
}
else
{
m_defaultMaterial->texture0->bind(0);
tmp_transparent = m_defaultMaterial->transparent;
}
// Set model matrix
program->setUniformValue("modelMatrix", it.modelMatrix);
// Set normal matrix
program->setUniformValue("normalMatrix", (normMatrix * it.modelMatrix).normalMatrix());
// set some material attributes
program->setUniformValue("material.shininess", shininess);
program->setUniformValue("material.specularColor", specularColor);
program->setUniformValue("material.isTransparent", tmp_transparent);
program->setUniformValue("material.hasSpecularmap", tmp_specular);
program->setUniformValue("material.hasNormalmap", tmp_normalmap);
program->setUniformValue("material.isGlow", tmp_glow);
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint)));
}
}
void GeometryEngine::loadFile(QString filePath)
{
@ -65,7 +194,7 @@ void GeometryEngine::loadFile(QString filePath)
//reset view
emit requestResetView();
emit sendMessage("loading file..", 0);
OutputDevice::getInstance()->print("loading file..", 0);
try
{
@ -74,7 +203,7 @@ void GeometryEngine::loadFile(QString filePath)
QVector<GLuint> indexData;
// open file and get the information
MshFile file(filePath, this);
MshFile file(filePath);
models = file.getModels();
m_materials = file.getMaterials();
@ -104,7 +233,7 @@ void GeometryEngine::loadFile(QString filePath)
vertexData += segmentIterator->vertices;
indexData += segmentIterator->indices;
if (segmentIterator->textureIndex < m_materials->size() && m_materials->at(segmentIterator->textureIndex).transparent)
if (segmentIterator->textureIndex < (unsigned) m_materials->size() && m_materials->at(segmentIterator->textureIndex).transparent)
m_drawList.push_back(new_info);
else
m_drawList.push_front(new_info);
@ -124,104 +253,13 @@ void GeometryEngine::loadFile(QString filePath)
m_indexBuf.allocate(indexData.data(), indexData.size() * sizeof(GLuint));
emit requestUpdate();
emit sendMessage("done..", 0);
emit sendFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3);
OutputDevice::getInstance()->print("done..", 0);
OutputDevice::getInstance()->setFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3);
}
catch (std::invalid_argument e)
{
clearData();
emit sendMessage(QString(e.what()), 2);
}
}
void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program, bool wireframe)
{
if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated())
return;
// Setup
// Tell OpenGL which VBOs to use
m_arrayBuf.bind();
m_indexBuf.bind();
// Allways normalize by this
QMatrix4x4 normMatrix;
float maxExtent = std::max(std::max(m_boundings.extents[0], m_boundings.extents[1]), m_boundings.extents[2]);
normMatrix.scale(1 / maxExtent);
normMatrix.translate(-m_boundings.center[0], -m_boundings.center[1], -m_boundings.center[2]);
program->setUniformValue("norm_matrix", normMatrix);
// Allways use texture unit 0
program->setUniformValue("texture", 0);
// Offset for position
quintptr offset = 0;
// Tell OpenGL programmable pipeline how to locate vertex position data
int vertexLocation = program->attributeLocation("a_position");
program->enableAttributeArray(vertexLocation);
program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
// Offset for texture coordinate
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
int texcoordLocation = program->attributeLocation("a_texcoord");
program->enableAttributeArray(texcoordLocation);
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
//Offset for normal
offset += sizeof(QVector2D);
// Tell OpenGL programmable pipeline how to locate vertex normal data
int normLocation = program->attributeLocation("a_normal");
program->enableAttributeArray(normLocation);
program->setAttributeBuffer(normLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
// Paint
for (auto& it : m_drawList)
{
bool tmp_transparent(false);
bool tmp_specular(false);
float shininess;
QVector3D specularColor;
// bind the correct texture
if (it.textureIndex < m_materials->size() && m_materials->at(it.textureIndex).texture0 != Q_NULLPTR)
{
m_materials->at(it.textureIndex).texture0->bind();
tmp_transparent = m_materials->at(it.textureIndex).transparent;
tmp_specular = m_materials->at(it.textureIndex).flags[7];
shininess = m_materials->at(it.textureIndex).shininess;
specularColor = m_materials->at(it.textureIndex).specularColor.toVector3D();
}
else
{
m_defaultMaterial->texture0->bind();
tmp_transparent = m_defaultMaterial->transparent;
}
// Set model matrix
program->setUniformValue("m_matrix", it.modelMatrix);
// Set normal matrix
program->setUniformValue("n_matrix", (normMatrix * it.modelMatrix).normalMatrix());
// set some more values
program->setUniformValue("b_transparent", tmp_transparent);
program->setUniformValue("b_specular", tmp_specular);
// set some material attributes
program->setUniformValue("materialShininess", shininess);
program->setUniformValue("materialSpecularColor", specularColor);
// Draw cube geometry using indices from VBO 1
if(wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint)));
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
OutputDevice::getInstance()->print(QString(e.what()), 2);
}
}

View File

@ -1,48 +1,57 @@
#include "..\Header\MainWindow.h"
#include "..\Header\OglViewerWidget.h"
#include <QSurfaceFormat>
#include <QMessageBox>
#include <QFileDialog>
#include <QPalette>
#include <QAction>
#include <QSignalMapper>
#include <QFile>
#include <QSizePolicy>
#include <QFont>
#include <QResizeEvent>
#include <QToolButton>
#include "..\Header\FileInterface.h"
#include "..\Header\OutputDevice.h"
#include <QSurfaceFormat>
#include <QSignalMapper>
#include <QToolButton>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QPalette>
#include <QResizeEvent>
#define WINDOW_NAME "Mesh Viewer"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindowClass)
, m_curSeverity(0)
, m_output(new QLabel(this))
, m_curSeverity(0)
, m_infoWindow(new FileInfoWindow(this))
{
// setup window
ui->setupUi(this);
setWindowTitle(WINDOW_NAME);
setWindowIcon(QIcon(":/images/icon.ico"));
connect(OutputDevice::getInstance(this), &OutputDevice::sendMessage, this, &MainWindow::printMessage);
connect(OutputDevice::getInstance(this), &OutputDevice::sendFileInfo, this, &MainWindow::setFileInfo);
// setup opengl things
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setMajorVersion(2);
format.setMinorVersion(0);
format.setProfile(QSurfaceFormat::NoProfile);
QSurfaceFormat::setDefaultFormat(format);
// set default text to file info
m_fileInfo = "Filename: -\nMaterials: -\nVertices: -\nTriangle: -<detail>No file is open";
// add widgets to the window
setupWidgets();
printMessage("MeshViewer by Anakin", 0);
m_fileInfo += "Filename: -\nMaterials: -\nVertices: -\nTriangle: -<detail>No file is open";
// load stylesheet
QFile styleSheet(":/files/StyleSheet.txt");
styleSheet.open(QIODevice::ReadOnly);
this->setStyleSheet(styleSheet.readAll());
getAssetLibrary();
printMessage("MeshViewer by Anakin", 0);
}
MainWindow::~MainWindow()
@ -52,68 +61,59 @@ MainWindow::~MainWindow()
delete m_infoWindow;
}
void MainWindow::openFile()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Mesh (*.msh)");
if(!fileName.isEmpty())
emit loadFile(fileName);
}
/////////////////////////////////////////////////////////////////////////
// functions
void MainWindow::setupWidgets()
{
// Ogl Viewer
OglViewerWidget* viewer = new OglViewerWidget(this);
setCentralWidget(viewer);
connect(viewer, &OglViewerWidget::sendMessage, this, &MainWindow::printMessage);
connect(this, &MainWindow::loadFile, viewer, &OglViewerWidget::loadFile);
// open file
QToolButton *openFile = new QToolButton(this);
openFile->setObjectName("openFile");
openFile->setToolTip("open file");
connect(openFile, &QToolButton::pressed, this, &MainWindow::openFile);
ui->mainToolBar->addWidget(openFile);
// screenshot
QToolButton *screenshot = new QToolButton(this);
screenshot->setObjectName("screenshot");
screenshot->setToolTip("take screenshot");
connect(screenshot, &QToolButton::pressed, this, &MainWindow::takeScreenShot);
ui->mainToolBar->addWidget(screenshot);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator();
QSignalMapper* signalMapper = new QSignalMapper(this);
// Free Camera
QToolButton *freeCamera = new QToolButton(this);
freeCamera->setObjectName("freeCamera");
freeCamera->setToolTip("free camera");
connect(freeCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useFreeCamera);
ui->mainToolBar->addWidget(freeCamera);
QToolButton *x = new QToolButton(this);
x->setObjectName("x");
x->setToolTip("x-direction");
x->setCheckable(true);
x->setChecked(true);
ui->mainToolBar->addWidget(x);
// Orbital Camera
QToolButton *orbitCamera = new QToolButton(this);
orbitCamera->setObjectName("orbitalCamera");
orbitCamera->setToolTip("orbital camera");
connect(orbitCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useOrbitCamera);
ui->mainToolBar->addWidget(orbitCamera);
QToolButton *y = new QToolButton(this);
y->setObjectName("y");
y->setToolTip("y-direction");
y->setCheckable(true);
y->setChecked(true);
ui->mainToolBar->addWidget(y);
QToolButton *z = new QToolButton(this);
z->setObjectName("z");
z->setToolTip("z-direction");
z->setCheckable(true);
z->setChecked(true);
ui->mainToolBar->addWidget(z);
connect(x, SIGNAL(pressed()), signalMapper, SLOT(map()));
connect(y, SIGNAL(pressed()), signalMapper, SLOT(map()));
connect(z, SIGNAL(pressed()), signalMapper, SLOT(map()));
signalMapper->setMapping(x, 1);
signalMapper->setMapping(y, 2);
signalMapper->setMapping(z, 3);
connect(signalMapper, SIGNAL(mapped(int)), viewer, SLOT(changeDirection(int)));
// Move Camera
QToolButton *walkCamera = new QToolButton(this);
walkCamera->setObjectName("walkCamera");
walkCamera->setToolTip("walk camera");
connect(walkCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useMoveCamera);
ui->mainToolBar->addWidget(walkCamera);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator();
// wireframe
QToolButton *wireframe = new QToolButton(this);
wireframe->setObjectName("wireframe");
wireframe->setToolTip("wireframe");
@ -122,6 +122,7 @@ void MainWindow::setupWidgets()
connect(wireframe, &QToolButton::pressed, viewer, &OglViewerWidget::toggleWireframe);
ui->mainToolBar->addWidget(wireframe);
// light
QToolButton *light = new QToolButton(this);
light->setObjectName("light");
light->setToolTip("toggle light");
@ -130,48 +131,79 @@ void MainWindow::setupWidgets()
connect(light, &QToolButton::pressed, viewer, &OglViewerWidget::toggleLight);
ui->mainToolBar->addWidget(light);
// settings
QToolButton *settings = new QToolButton(this);
settings->setObjectName("settings");
settings->setToolTip("settings");
connect(settings, &QToolButton::pressed, viewer, &OglViewerWidget::showSettings);
ui->mainToolBar->addWidget(settings);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator();
// fileinfo
QToolButton *fileInfo = new QToolButton(this);
fileInfo->setObjectName("fileInfo");
fileInfo->setToolTip("file info");
connect(fileInfo, &QToolButton::pressed, this, &MainWindow::aboutFile);
connect(fileInfo, &QToolButton::pressed, m_infoWindow, &FileInfoWindow::show);
ui->mainToolBar->addWidget(fileInfo);
// help
QToolButton *help = new QToolButton(this);
help->setObjectName("help");
help->setToolTip("help");
connect(help, &QToolButton::pressed, this, &MainWindow::aboutTool);
ui->mainToolBar->addWidget(help);
// output on screen
m_output->setObjectName("output");
m_output->setStyleSheet("QLabel#output{color : white; min-width: 400px; min-height: 50px;}");
m_output->setAlignment(Qt::AlignTop);
m_output->setText("Name: -\nMaterials: -\nVertice: -\nTriangle: -");
m_output->setText(m_fileInfo.left(m_fileInfo.indexOf("<detail>")));
m_output->raise();
}
void MainWindow::aboutFile()
void MainWindow::getAssetLibrary()
{
/*QMessageBox* dialog = new QMessageBox(QMessageBox::NoIcon,
WINDOW_NAME,
QString(m_fileInfo.left(m_fileInfo.indexOf("<detail>"))),
QMessageBox::StandardButton::Close,
this,
Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setData(0, Qt::DisplayRole, "Wuhu");
ui->treeWidget->addTopLevelItem(item);
dialog->setStyleSheet("QLabel{min-width: 200px;}");
dialog->setDetailedText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("<detail>") - 8)));
dialog->exec();
delete dialog;*/
m_infoWindow->show();
searchMeshFiles("D:/workspaces/Visual Studio 2015/Projects/OpenGL/Release");
}
void MainWindow::searchMeshFiles(QString path)
{
QDir directory(path);
directory.setNameFilters(QStringList("*.msh"));
QStringList childDirectories = directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
QStringList fileNames = directory.entryList(QDir::Files);
for (auto &it : childDirectories)
qDebug() << it;
for (auto &it : fileNames)
qDebug() << it;
}
void MainWindow::openFile()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Mesh (*.msh)");
if(!fileName.isEmpty())
emit loadFile(fileName);
}
void MainWindow::takeScreenShot()
{
QString destination = QFileDialog::getSaveFileName(this, "Save as...", "", "PNG (*.png);; BMP (*.bmp);;TIFF (*.tiff, *.tif);;JPEG (*.jpg *jpeg)");
OglViewerWidget* viewer = dynamic_cast<OglViewerWidget*>(centralWidget());
if (!destination.isEmpty() && viewer != NULL)
viewer->grab().save(destination);
}
void MainWindow::aboutTool()
@ -193,22 +225,48 @@ void MainWindow::aboutTool()
delete dialog;
}
void MainWindow::takeScreenShot()
{
QString destination = QFileDialog::getSaveFileName(this, "Save as...", "", "PNG (*.png);; BMP (*.bmp);;TIFF (*.tiff, *.tif);;JPEG (*.jpg *jpeg)");
OglViewerWidget* viewer = dynamic_cast<OglViewerWidget*>(centralWidget());
if (!destination.isEmpty() && viewer != NULL)
viewer->grab().save(destination);
}
void MainWindow::resizeEvent(QResizeEvent * e)
{
m_output->move(40, e->size().height() - 80);
}
/////////////////////////////////////////////////////////////////////////
// slots
void MainWindow::printMessage(QString message, int severity)
{
if (!ui->statusBar->currentMessage().isEmpty() && severity < m_curSeverity)
return;
m_curSeverity = severity;
int time(0);
QPalette palette;
switch (severity)
{
case 1:
time = 3000;
palette.setColor(QPalette::WindowText, Qt::darkYellow);
break;
case 2:
time = 3000;
palette.setColor(QPalette::WindowText, Qt::red);
break;
case 0:
default:
time = 2000;
palette.setColor(QPalette::WindowText, Qt::black);
break;
}
ui->statusBar->setPalette(palette);
ui->statusBar->showMessage(message, time);
}
void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle)
{
// save basic file information
m_fileInfo = QByteArray("Filename: ");
m_fileInfo += name;
m_fileInfo += "\nMaterials: ";
@ -219,6 +277,7 @@ void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int ver
m_fileInfo += QByteArray::number(triangle);
m_fileInfo += "<detail>";
// add detailed information
for (auto& it : *materials)
{
m_fileInfo += it.name;
@ -307,39 +366,11 @@ void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int ver
m_fileInfo += "-----------------------------------------------------------------\n";
}
// print basic information on screen
m_output->setText(m_fileInfo.left(m_fileInfo.indexOf("<detail>")));
// print basic and detailed information on info window
m_infoWindow->setBasicText(QString(m_fileInfo.left(m_fileInfo.indexOf("<detail>"))));
m_infoWindow->setDetailText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("<detail>") - 8)));
}
void MainWindow::printMessage(QString message, int severity)
{
if (!ui->statusBar->currentMessage().isEmpty() && severity < m_curSeverity)
return;
m_curSeverity = severity;
int time(0);
QPalette palette;
switch (severity)
{
case 1:
time = 3000;
palette.setColor(QPalette::WindowText, Qt::darkYellow);
break;
case 2:
time = 3000;
palette.setColor(QPalette::WindowText, Qt::red);
break;
case 0:
default:
time = 2000;
palette.setColor(QPalette::WindowText, Qt::black);
break;
}
ui->statusBar->setPalette(palette);
ui->statusBar->showMessage(message, time);
}

View File

@ -0,0 +1,82 @@
#include "..\Header\MoveCamera.h"
#include <QVector2D>
#include <qmath.h>
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
MoveCamera::MoveCamera()
{
resetView();
}
MoveCamera::~MoveCamera()
{
}
/////////////////////////////////////////////////////////////////////////
// functions
void MoveCamera::rotateAction(QVector2D diff)
{
m_phi -= diff.x() * 0.01;
m_theta += diff.y() * 0.01;
m_theta = qMax(qMin(M_PI - 0.0001, m_theta), 0.0001);
}
void MoveCamera::moveAction(QVector2D diff)
{
if (diff.y() > 0)
m_sidewardSpeed = 1;
else if (diff.y() < 0)
m_sidewardSpeed = -1;
else
m_sidewardSpeed = 0;
}
void MoveCamera::wheelAction(double value)
{
if (value > 0)
m_forwardSpeed = 1;
else if (value < 0)
m_forwardSpeed = -1;
else
m_forwardSpeed = 0;
}
void MoveCamera::recalculateMatrix()
{
m_matrix = QMatrix4x4();
// different coordinate (spherical -> world) X->Z | Y->X | Z->Y
QVector3D tmpdirection(
qSin(m_theta) * qSin(m_phi),
qCos(m_theta),
qSin(m_theta) * qCos(m_phi)
);
QVector3D tmpRight(
qSin(m_phi - M_PI_2),
0,
qCos(m_phi - M_PI_2)
);
m_position += m_forwardSpeed * m_zSpeed * 0.1 * tmpdirection;
m_position += m_sidewardSpeed * m_zSpeed * 0.1 * tmpRight;
m_matrix.lookAt(m_position, m_position + tmpdirection, QVector3D::crossProduct(tmpRight, tmpdirection));
}
void MoveCamera::resetView()
{
m_position = { 0,0,4 };
m_phi = M_PI;
m_theta = M_PI_2;
m_forwardSpeed = 0;
m_sidewardSpeed = 0;
CameraInterface::resetView();
}

View File

@ -1,6 +1,8 @@
#include "..\Header\MshFile.h"
#include "..\Header\tga.h"
#include <QColor>
#include "..\Header\OutputDevice.h"
#include <QVector3D>
// helper function to save data from file to any variable type
#define F2V(variableName) reinterpret_cast<char*>(&variableName)
@ -9,8 +11,8 @@
/////////////////////////////////////////////////////////////////////////
// public constructor/destructor
MshFile::MshFile(QString path, QObject * parent)
: FileInterface(path, parent)
MshFile::MshFile(QString path)
: FileInterface(path)
{
import();
}
@ -26,22 +28,22 @@ MshFile::~MshFile()
void MshFile::import()
{
// go to file size information
m_file.seekg(4);
m_file.seek(4);
std::uint32_t tmp_fileSize;
std::list<ChunkHeader*> tmp_mainChunks;
quint32 tmp_fileSize;
QList<ChunkHeader*> tmp_mainChunks;
// get all chunks under HEDR
m_file.read(F2V(tmp_fileSize), sizeof(tmp_fileSize));
loadChunks(tmp_mainChunks, m_file.tellg(), tmp_fileSize);
loadChunks(tmp_mainChunks, m_file.pos(), tmp_fileSize);
// evaulate HEDR subchunks (= find MSH2)
for (ChunkHeader* it : tmp_mainChunks)
{
if (!strcmp("MSH2", it->name))
if ("MSH2" == it->name)
{
// get all subchunks
std::list<ChunkHeader*> tmp_msh2Chunks;
QList<ChunkHeader*> tmp_msh2Chunks;
loadChunks(tmp_msh2Chunks, it->position, it->size);
// evaluate MSH2 subchunks
@ -66,54 +68,57 @@ void MshFile::import()
}
}
void MshFile::loadChunks(std::list<ChunkHeader*>& destination, std::streampos start, const std::uint32_t length)
void MshFile::loadChunks(QList<ChunkHeader*>& destination, qint64 start, const quint32 length)
{
// jump to first chunk
m_file.seekg(start);
m_file.seek(start);
do
{
// out of file. Maybe a size information is corrupted
if (m_file.atEnd() || m_file.error() != QFileDevice::NoError)
{
OutputDevice::getInstance()->print("WARNING: corrupted file. Trying to continue..", 1);
m_file.unsetError();
m_file.seek(0);
break;
}
ChunkHeader* tmp_header = new ChunkHeader();
// get information
m_file.read(F2V(tmp_header->name[0]), sizeof(tmp_header->name) - 1);
char tmpName[5] = { 0 };
m_file.read(F2V(tmpName[0]), sizeof(tmpName) -1);
tmp_header->name = QString(tmpName);
m_file.read(F2V(tmp_header->size), sizeof(tmp_header->size));
tmp_header->position = m_file.tellg();
tmp_header->position = m_file.pos();
// store information
destination.push_back(tmp_header);
// jump to next header
m_file.seekg(tmp_header->size, std::ios_base::cur);
m_file.seek(tmp_header->size + m_file.pos());
// out of file. Maybe a size information is corrupted
if (!m_file.good())
{
emit sendMessage("WARNING: corrupted file. Trying to continue..", 1);
m_file.clear();
break;
}
} while (m_file.tellg() - start != length);
} while (m_file.pos() - start != length);
}
void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
void MshFile::analyseMsh2Chunks(QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// scene information
if (!strcmp("SINF", it->name))
if ("SINF" == it->name)
{
// get SINF subchunks
std::list<ChunkHeader*> tmp_sinfChunks;
QList<ChunkHeader*> tmp_sinfChunks;
loadChunks(tmp_sinfChunks, it->position, it->size);
// evaluate SINF subchunks
for (auto& it : tmp_sinfChunks)
{
if (!strcmp("BBOX", it->name))
if ("BBOX" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
// read in the quaternion
float tmp_quat[4];
@ -141,24 +146,25 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
}
// material list
else if (!strcmp("MATL", it->name))
else if ("MATL" == it->name)
{
OutputDevice::getInstance()->print("loading materials..", 0);
// "useless" information how many MATD follow, jump over it
m_file.seekg(it->position);
m_file.seekg(sizeof(std::uint32_t), std::ios_base::cur);
m_file.seek(it->position);
m_file.seek(sizeof(quint32) + m_file.pos());
// get all MATL subchunk
std::list<ChunkHeader*> tmp_matlChunks;
loadChunks(tmp_matlChunks, m_file.tellg(), it->size - 4);
QList<ChunkHeader*> tmp_matlChunks;
loadChunks(tmp_matlChunks, m_file.pos(), it->size - 4);
// evaluate MATL subchunks
for (auto& it : tmp_matlChunks)
{
// This shouldn't be anything else than MATD
if (!strcmp("MATD", it->name))
if ("MATD" == it->name)
{
// get all subchunks from MATD
std::list<ChunkHeader*> tmp_matdChunks;
QList<ChunkHeader*> tmp_matdChunks;
loadChunks(tmp_matdChunks, it->position, it->size);
m_materials->push_back(Material());
@ -186,14 +192,15 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
}
// model
else if (!strcmp("MODL", it->name))
else if ("MODL" == it->name)
{
OutputDevice::getInstance()->print("loading model..", 0);
Model* new_model = new Model;
m_currentType = ModelTyp::null;
m_currentRenderFlag = -1;
// get all MODL subchunks
std::list<ChunkHeader*> tmp_chunks;
QList<ChunkHeader*> tmp_chunks;
loadChunks(tmp_chunks, it->position, it->size);
// evaluate MODL subchunks
@ -213,14 +220,14 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
}
}
void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
void MshFile::analyseMatdChunks(QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// name
if (!strcmp("NAME", it->name))
if ("NAME" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -229,9 +236,9 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
}
// data
else if(!strcmp("DATA", it->name))
else if("DATA" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
// diffuse
for (unsigned int i = 0; i < 4; i++)
@ -250,18 +257,18 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
}
// attributes
else if (!strcmp("ATRB", it->name))
else if ("ATRB" == it->name)
{
// get pointer to current material
Material* curMat = &m_materials->back();
// read the attributes
m_file.seekg(it->position);
std::uint8_t flag;
m_file.seek(it->position);
quint8 flag;
m_file.read(F2V(flag), sizeof(flag));
m_file.read(F2V(curMat->rendertype), sizeof(std::uint8_t));
m_file.read(F2V(curMat->dataValues[0]), sizeof(std::uint8_t));
m_file.read(F2V(curMat->dataValues[1]), sizeof(std::uint8_t));
m_file.read(F2V(curMat->rendertype), sizeof(quint8));
m_file.read(F2V(curMat->dataValues[0]), sizeof(quint8));
m_file.read(F2V(curMat->dataValues[1]), sizeof(quint8));
// flags
// 0: emissive
@ -274,17 +281,16 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
// 7: specular
for (unsigned int i = 0; i < 8; i++)
curMat->flags[i] = (std::uint8_t)(flag << (7 - i)) >> 7;
curMat->flags[i] = (quint8)(flag << (7 - i)) >> 7;
curMat->transparent = curMat->flags[2] || curMat->flags[3] || curMat->flags[4] || curMat->flags[6] || curMat->rendertype == 4;
}
// texture 0
else if (!strcmp("TX0D", it->name))
else if ("TX0D" == it->name)
{
// get the texture name
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -297,10 +303,10 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
}
// texture 1
else if (!strcmp("TX1D", it->name))
else if ("TX1D" == it->name)
{
// get the texture name
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -309,14 +315,13 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
if (!m_materials->back().tx1d.isEmpty())
loadTexture(m_materials->back().texture1, m_filepath, m_materials->back().tx1d);
}
// texture 2
else if (!strcmp("TX2D", it->name))
else if ("TX2D" == it->name)
{
// get the texture name
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -325,10 +330,10 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
}
// texture 3
else if (!strcmp("TX3D", it->name))
else if ("TX3D" == it->name)
{
// get the texture name
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -338,23 +343,23 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
}
}
void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseModlChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// model type
if (!strcmp("MTYP", it->name))
if ("MTYP" == it->name)
{
m_file.seekg(it->position);
std::uint32_t tmp_type;
m_file.seek(it->position);
quint32 tmp_type;
m_file.read(F2V(tmp_type), sizeof(tmp_type));
m_currentType = (ModelTyp)tmp_type;
}
// parent name
else if (!strcmp("PRNT", it->name))
else if ("PRNT" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -363,9 +368,9 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// model name
else if (!strcmp("NAME", it->name))
else if ("NAME" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -374,20 +379,20 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// render flags
else if (!strcmp("FLGS", it->name))
else if ("FLGS" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
m_file.read(F2V(m_currentRenderFlag), sizeof(m_currentRenderFlag));
}
// translation
else if (!strcmp("TRAN", it->name))
else if ("TRAN" == it->name)
{
float tmp_scale[3];
float tmp_rotation[4];
float tmp_trans[3];
m_file.seekg(it->position);
m_file.seek(it->position);
// read in the data
for (int i = 0; i < 3; i++)
@ -410,14 +415,14 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// geometry data
else if (!strcmp("GEOM", it->name))
else if ("GEOM" == it->name)
{
// don't get null, bone, shadowMesh and hidden mesh indices
if (m_currentType == null || m_currentType == bone || m_currentType == shadowMesh || m_currentRenderFlag == 1)
continue;
// get all GEOM subchunks
std::list<ChunkHeader*> tmp_geomChunks;
QList<ChunkHeader*> tmp_geomChunks;
loadChunks(tmp_geomChunks, it->position, it->size);
// evaluate GEOM subchunks
@ -434,15 +439,15 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
}
void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseGeomChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// segment
if (!strcmp("SEGM", it->name))
if ("SEGM" == it->name)
{
// get all SEGM subchunks
std::list<ChunkHeader*> tmp_segmChunks;
QList<ChunkHeader*> tmp_segmChunks;
loadChunks(tmp_segmChunks, it->position, it->size);
// evaluate SEGM subchunks
@ -458,10 +463,10 @@ void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// cloth
else if (!strcmp("CLTH", it->name))
else if ("CLTH" == it->name)
{
// get all CLTH subchunks
std::list<ChunkHeader*> tmp_clthChunks;
QList<ChunkHeader*> tmp_clthChunks;
loadChunks(tmp_clthChunks, it->position, it->size);
// evaluate CLTH subchunks
@ -478,43 +483,43 @@ void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>
}
}
void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseSegmChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
Segment* new_segment = new Segment;
for (auto& it : chunkList)
{
// material index
if (!strcmp("MATI", it->name))
if ("MATI" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
m_file.read(F2V(new_segment->textureIndex), sizeof(new_segment->textureIndex));
}
// position list (vertex)
else if (!strcmp("POSL", it->name))
else if ("POSL" == it->name)
{
readVertex(new_segment, it->position);
}
// normals
else if (!strcmp("NRML", it->name))
else if ("NRML" == it->name)
{
std::uint32_t tmp_size;
m_file.seekg(it->position);
quint32 tmp_size;
m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
if (tmp_size < new_segment->vertices.size())
if (tmp_size < (unsigned) new_segment->vertices.size())
{
emit sendMessage("WARNING: too less normals " + QString::number(tmp_size) + " < " + QString::number(new_segment->vertices.size()), 1);
OutputDevice::getInstance()->print("WARNING: too less normals " + QString::number(tmp_size) + " < " + QString::number(new_segment->vertices.size()), 1);
for (unsigned int i = new_segment->vertices.size(); i != tmp_size; i--)
for (unsigned int j = 0; j < 3; j++)
new_segment->vertices[i - 1].vertexNormal[j] = 0;
}
else if (tmp_size > new_segment->vertices.size())
else if (tmp_size > (unsigned) new_segment->vertices.size())
{
emit sendMessage("WARNING: too many normals " + QString::number(tmp_size) + " > " + QString::number(new_segment->vertices.size()), 1);
OutputDevice::getInstance()->print("WARNING: too many normals " + QString::number(tmp_size) + " > " + QString::number(new_segment->vertices.size()), 1);
tmp_size = new_segment->vertices.size();
}
@ -525,18 +530,18 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// uv
else if (!strcmp("UV0L", it->name))
else if ("UV0L" == it->name)
{
readUV(new_segment, it->position);
}
// polygons (indices into vertex/uv list)
else if (!strcmp("STRP", it->name))
else if ("STRP" == it->name)
{
// jump to the data section and read the size;
std::uint32_t tmp_size;
m_file.seekg(it->position);
quint32 tmp_size;
m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
int highBitCount(0);
@ -545,7 +550,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
for (unsigned int i = 0; i < tmp_size; i++)
{
// ReadData
std::uint16_t tmp_value;
quint16 tmp_value;
m_file.read(F2V(tmp_value), sizeof(tmp_value));
// Check if highbit is set
@ -553,7 +558,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
{
highBitCount++;
// remove the high bit, to get the actually value
tmp_value = (std::uint16_t(tmp_value << 1) >> 1);
tmp_value = (quint16(tmp_value << 1) >> 1);
}
// save data
@ -567,18 +572,106 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
if (tmp_buffer.size() == 5)
{
for (size_t i = 0; i < 3; i++)
new_segment->indices.push_back(tmp_buffer.takeFirst());
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
for (int k = 0; k < 3; k++)
{
// polygon normal wasn't calculated before
if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
new_segment->vertices[tmp_buffer[k]].tangent = tan;
new_segment->vertices[tmp_buffer[k]].bitangent = bi;
new_segment->indices.push_back(tmp_buffer[k]);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
tmp_buffer.remove(0, 3);
}
else if (tmp_buffer.size() > 5)
{
unsigned int tmp_multiPolySize = tmp_buffer.size() - 2;
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
// for every triangle of the multi polygon..
for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
{
// ..calculate the edge indices
for (int triEdge = 0; triEdge < 3; triEdge++)
new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
{
int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];
// polygon normal wasn't calculated before
if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[curIndi].polygonNormal = norm;
new_segment->vertices[curIndi].tangent = tan;
new_segment->vertices[curIndi].bitangent = bi;
new_segment->indices.push_back(curIndi);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[curIndi]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
}
tmp_buffer.remove(0, tmp_multiPolySize);
}
@ -589,17 +682,106 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
// save the last polygon (no 2 high bit followed)
if (tmp_buffer.size() == 3)
{
for (size_t i = 0; i < 3; i++)
new_segment->indices.push_back(tmp_buffer.takeFirst());
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
for (int k = 0; k < 3; k++)
{
// polygon normal wasn't calculated before
if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
new_segment->vertices[tmp_buffer[k]].tangent = tan;
new_segment->vertices[tmp_buffer[k]].bitangent = bi;
new_segment->indices.push_back(tmp_buffer[k]);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
tmp_buffer.remove(0, 3);
}
else if (tmp_buffer.size() > 3)
{
unsigned int tmp_multiPolySize = tmp_buffer.size();
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
// for every triangle of the multi polygon..
for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
{
// ..calculate the edge indices
for (int triEdge = 0; triEdge < 3; triEdge++)
new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
{
int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];
// polygon normal wasn't calculated before
if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[curIndi].polygonNormal = norm;
new_segment->vertices[curIndi].tangent = tan;
new_segment->vertices[curIndi].bitangent = bi;
new_segment->indices.push_back(curIndi);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[curIndi]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
}
}
}
}
@ -607,17 +789,17 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
dataDestination->segmList.push_back(new_segment);
}
void MshFile::analyseClthChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseClthChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
Segment* new_segment = new Segment;
for (auto& it : chunkList)
{
// texture name
if (!strcmp("CTEX", it->name))
if ("CTEX" == it->name)
{
// read the texture name
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -638,32 +820,46 @@ void MshFile::analyseClthChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// position list (vertex)
else if (!strcmp("CPOS", it->name))
else if ("CPOS" == it->name)
{
readVertex(new_segment, it->position);
}
// uv
else if (!strcmp("CUV0", it->name))
else if ("CUV0" == it->name)
{
readUV(new_segment, it->position);
}
// triangles (indices into vertex/uv list)
else if (!strcmp("CMSH", it->name))
else if ("CMSH" == it->name)
{
// jump to the data section and read the size;
std::uint32_t tmp_size;
m_file.seekg(it->position);
quint32 tmp_size;
m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
// for every triangle..
for (unsigned int i = 0; i < tmp_size * 3; i++)
for (unsigned int i = 0; i < tmp_size; i++)
{
std::uint32_t tmp_value;
m_file.read(F2V(tmp_value), sizeof(std::uint32_t));
quint32 tmp_value[3];
for (unsigned int j = 0; j < 3; j++)
{
m_file.read(F2V(tmp_value[j]), sizeof(quint32));
new_segment->indices.push_back((GLuint)tmp_value[j]);
}
new_segment->indices.push_back((GLuint)tmp_value);
QVector3D vec1, vec2, norm;
vec1 = new_segment->vertices[new_segment->indices[i * 3]].position - new_segment->vertices[new_segment->indices[i * 3 + 1]].position;
vec2 = new_segment->vertices[new_segment->indices[i * 3]].position - new_segment->vertices[new_segment->indices[i * 3 + 2]].position;
norm = QVector3D::crossProduct(vec1, vec2);
for (int k = 0; k < 3; k++)
{
new_segment->vertices[new_segment->indices[i * 3 + k]].vertexNormal += norm;
new_segment->vertices[new_segment->indices[i * 3 + k]].vertexNormal.normalize();
}
}
}
}
@ -671,10 +867,10 @@ void MshFile::analyseClthChunks(Model * dataDestination, std::list<ChunkHeader*>
dataDestination->segmList.push_back(new_segment);
}
void MshFile::readVertex(Segment * dataDestination, std::streampos position)
void MshFile::readVertex(Segment * dataDestination, qint64 position)
{
std::uint32_t tmp_size;
m_file.seekg(position);
quint32 tmp_size;
m_file.seek(position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
for (unsigned int i = 0; i < tmp_size; i++)
@ -690,23 +886,23 @@ void MshFile::readVertex(Segment * dataDestination, std::streampos position)
}
}
void MshFile::readUV(Segment * dataDestination, std::streampos position)
void MshFile::readUV(Segment * dataDestination, qint64 position)
{
std::uint32_t tmp_size;
m_file.seekg(position);
quint32 tmp_size;
m_file.seek(position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
if (tmp_size < dataDestination->vertices.size())
if (tmp_size < (unsigned) dataDestination->vertices.size())
{
emit sendMessage("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
OutputDevice::getInstance()->print("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
for (unsigned int i = dataDestination->vertices.size(); i != tmp_size; i--)
for (unsigned int j = 0; j < 2; j++)
dataDestination->vertices[i - 1].texCoord[j] = 0;
}
else if (tmp_size > dataDestination->vertices.size())
else if (tmp_size > (unsigned) dataDestination->vertices.size())
{
emit sendMessage("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
OutputDevice::getInstance()->print("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
tmp_size = dataDestination->vertices.size();
}
@ -718,12 +914,13 @@ void MshFile::readUV(Segment * dataDestination, std::streampos position)
void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
{
bool loadSuccess(false);
QImage img = loadTga(filepath + "/" + filename, loadSuccess);
if (!loadSuccess)
{
emit sendMessage("WARNING: texture not found or corrupted: " + filename, 1);
OutputDevice::getInstance()->print("WARNING: texture not found or corrupted: " + filename, 1);
//TODO: cloth use the wrong diffuse color. should be null
img = QImage(1, 1, QImage::Format_RGB32);
img.fill(QColor(m_materials->back().diffuseColor[0] * 255, m_materials->back().diffuseColor[1] * 255, m_materials->back().diffuseColor[2] * 255));
filename += " *";
@ -745,13 +942,13 @@ void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QStri
destination = new_texture;
}
QMatrix4x4 MshFile::getParentMatrix(std::string parent) const
QMatrix4x4 MshFile::getParentMatrix(QString parent) const
{
QMatrix4x4 matrix;
for (auto& it : *m_models)
{
if (!strcmp(parent.c_str(), it->name.c_str()))
if (parent == it->name)
{
matrix = getParentMatrix(it->parent) * it->m4x4Translation;
break;
@ -761,13 +958,13 @@ QMatrix4x4 MshFile::getParentMatrix(std::string parent) const
return matrix;
}
QQuaternion MshFile::getParentRotation(std::string parent) const
QQuaternion MshFile::getParentRotation(QString parent) const
{
QQuaternion rotation;
for (auto& it : *m_models)
{
if (!strcmp(parent.c_str(), it->name.c_str()))
if (parent == it->name)
{
rotation = getParentRotation(it->parent) * it->quadRotation;
break;

View File

@ -1,31 +1,41 @@
#include "..\Header\OglViewerWidget.h"
#include "..\Header\MainWindow.h"
#include "..\Header\FreeCamera.h"
#include "..\Header\OrbitCamera.h"
#include "..\Header\MoveCamera.h"
#include "..\Header\SettingsManager.h"
#include <QMouseEvent>
#include <QDropEvent>
#include <QMimeData>
#include <math.h>
#include <iostream>
#include "..\Header\Profiler.h"
#define DEFAULT_Z_DISTANCE -4.0
/////////////////////////////////////////////////////////////////////////
// public constructor/destructor
// constructor/destructor
OglViewerWidget::OglViewerWidget(QWidget *parent)
: QOpenGLWidget(parent)
, m_dataEngine(0)
, m_settings(new SettingsWindow(this))
, m_dataEngine(Q_NULLPTR)
, m_camera(new FreeCamera)
{
setFocus();
m_translation.setZ(DEFAULT_Z_DISTANCE);
setAcceptDrops(true);
// settings window
setDefaultValues();
m_settings = new SettingsWindow(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);
connect(m_settings, &SettingsWindow::updateAttFac, this, &OglViewerWidget::setAttFac);
connect(m_settings, &SettingsWindow::updateAmbCoef, this, &OglViewerWidget::setAmbCoef);
connect(m_settings, &SettingsWindow::sendHeadlight, this, &OglViewerWidget::setHeadlight);
connect(m_settings, &SettingsWindow::sendBackfaceCulling, this, &OglViewerWidget::setBackfaceCulling);
connect(m_settings, &SettingsWindow::sendZommSpeed, [this](int value) {m_camera->setZoomSpeed(value); });
}
OglViewerWidget::~OglViewerWidget()
@ -36,12 +46,155 @@ OglViewerWidget::~OglViewerWidget()
delete m_dataEngine;
doneCurrent();
delete m_camera;
delete m_settings;
}
/////////////////////////////////////////////////////////////////////////
// protected functions
// functions
void OglViewerWidget::setDefaultValues()
{
SettingsManager* sm = SettingsManager::getInstance(this);
m_backgroundColorOn = QVector4D(sm->getBgColorOn() / 255, 1.0f);
m_backgroundColorOff = QVector4D(sm->getBgColorOff() / 255, 1.0f);
m_wireframe = false;
m_lightOn = sm->isLight();
m_backfaceCulling = sm->isBfCulling();
if (sm->getLightType() == 1) // directional
m_light.position = { 0.0,0.0,0.0,0.0 };
else // point
m_light.position = { 0.0,0.0,0.0,1.0 };
m_light.intensities = sm->getLightColor() / 255;
m_light.attenuationFactor = sm->getAttenuation();
m_light.ambientCoefficient = sm->getAmbient();
m_light.headlight = sm->isHeadlight();
connect(this, &OglViewerWidget::lightChanged, sm, &SettingsManager::setLight);
}
void OglViewerWidget::initShaders()
{
// Compile vertex shader
if (!m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl"))
close();
// Compile fragment shader
if (!m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl"))
close();
// Link shader pipeline
if (!m_program.link())
close();
// Bind shader pipeline for use
if (!m_program.bind())
close();
}
void OglViewerWidget::resetView()
{
m_camera->resetView();
if (m_light.headlight)
updateLightPosition();
update();
}
void OglViewerWidget::updateLightPosition()
{
QVector4D lightPosition = { 0,0,0,1 };
lightPosition = m_camera->getMatrix().inverted() * lightPosition;
m_light.position.setX(lightPosition.x());
m_light.position.setY(lightPosition.y());
m_light.position.setZ(lightPosition.z());
}
// OpenGL ///////////////////////////////////////////////////////////////
void OglViewerWidget::initializeGL()
{
initializeOpenGLFunctions();
initShaders();
// Enable depth buffer
glEnable(GL_DEPTH_TEST);
// Enable transparency
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_dataEngine = new GeometryEngine(this);
connect(m_dataEngine, &GeometryEngine::requestResetView, this, &OglViewerWidget::resetView);
connect(m_dataEngine, &GeometryEngine::requestUpdate, this, static_cast<void(OglViewerWidget::*)(void)>(&OglViewerWidget::update));
}
void OglViewerWidget::resizeGL(int w, int h)
{
// Calculate aspect ratio
qreal aspect = qreal(w) / qreal(h ? h : 1);
// Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
const qreal zNear = 0.1, zFar = 100.0, fov = 45.0;
// Reset projection
m_projection.setToIdentity();
// Set perspective projection
m_projection.perspective(fov, aspect, zNear, zFar);
}
void OglViewerWidget::paintGL()
{
// set background color, last value is dirtybit
if (m_lightOn && m_backgroundColorOn[3] == 1.0)
{
glClearColor(m_backgroundColorOn[0], m_backgroundColorOn[1], m_backgroundColorOn[2], 0.0000f);
m_backgroundColorOn[3] = 0.0;
}
else if (!m_lightOn && m_backgroundColorOff[3] == 1.0)
{
glClearColor(m_backgroundColorOff[0], m_backgroundColorOff[1], m_backgroundColorOff[2], 0.0000f);
m_backgroundColorOff[3] = 0.0;
}
// Clear color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set view-projection matrix
m_program.setUniformValue("viewProjection", m_projection * m_camera->getMatrix());
// Set Light values
m_program.setUniformValue("useLight", m_lightOn);
m_program.setUniformValue("light.position", m_light.position);
m_program.setUniformValue("light.intensities", m_light.intensities);
m_program.setUniformValue("light.attenuationFactor", m_light.attenuationFactor);
m_program.setUniformValue("light.ambientCoefficient", m_light.ambientCoefficient);
// Set camera position
m_program.setUniformValue("cameraPosition", (m_camera->getMatrix().inverted() * QVector4D(0,0,0,1)).toVector3D());
// Draw cube geometry
if (m_backfaceCulling)
glEnable(GL_CULL_FACE);
if (m_wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
m_dataEngine->drawGeometry(&m_program);
glDisable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
// Inputs ///////////////////////////////////////////////////////////////
void OglViewerWidget::mousePressEvent(QMouseEvent *e)
{
@ -68,95 +221,109 @@ void OglViewerWidget::mouseMoveEvent(QMouseEvent *e)
if (m_mouse.left)
{
// get the difference between last press and now
QVector2D diff = QVector2D(e->localPos()) - m_mouse.position;
m_camera->rotateAction(QVector2D(e->localPos()) - m_mouse.position);
// update the new position
m_mouse.position = QVector2D(e->localPos());
// calculate the rotation axis and rotate
if (m_rotDirections.x && m_rotDirections.y && m_rotDirections.z)
{
m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(diff.y(), diff.x(), 0.0).normalized(), diff.length() * 0.5) * m_rotation;
}
else if (m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z)
{
float pitch, yaw, roll;
m_rotation.getEulerAngles(&pitch, &yaw, &roll);
pitch += diff.y() * 0.5;
yaw += diff.x() * 0.5;
if (pitch > 89)
pitch = 89;
else if (pitch < -89)
pitch = -89;
m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll);
}
else if (m_rotDirections.x && !m_rotDirections.y && !m_rotDirections.z)
{
m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(0.0, 1.0, 0.0).normalized(), diff.x() * 0.5) * m_rotation;
}
else if (!m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z)
{
m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(1.0, 0.0, 0.0).normalized(), diff.y() * 0.5) * m_rotation;
}
else if (!m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z)
{
m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(0.0, 0.0, 1.0).normalized(), diff.x() * 0.5) * m_rotation;
}
else if (m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z)
{
float pitch, yaw, roll;
m_rotation.getEulerAngles(&pitch, &yaw, &roll);
roll -= diff.y() * 0.5;
yaw += diff.x() * 0.5;
m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll);
}
else if (!m_rotDirections.x && m_rotDirections.y && m_rotDirections.z)
{
float pitch, yaw, roll;
m_rotation.getEulerAngles(&pitch, &yaw, &roll);
pitch += diff.y() * 0.5;
roll += diff.x() * 0.5;
if (pitch > 89)
pitch = 89;
else if (pitch < -89)
pitch = -89;
m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll);
}
// request an update
if (m_light.headlight)
updateLightPosition();
update();
}
else if (m_mouse.right)
{
// get the difference between last press and now
QVector2D diff = QVector2D(e->localPos()) - m_mouse.position;
m_camera->moveAction(QVector2D(e->localPos()) - m_mouse.position);
// update the new position
m_mouse.position = QVector2D(e->localPos());
// calculate the translation
m_translation += {(float)(diff.x() * 0.01), (float)(diff.y() * -0.01), 0.0};
// request an update
if (m_light.headlight)
updateLightPosition();
update();
}
}
void OglViewerWidget::wheelEvent(QWheelEvent *e)
{
m_translation += {0.0, 0.0, (float)m_zSpeed * e->angleDelta().y() / 240};
m_camera->wheelAction(e->angleDelta().y());
if (m_light.headlight)
updateLightPosition();
update();
}
void OglViewerWidget::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Space)
{
resetView();
}
else if (e->key() == Qt::Key_W)
{
emit m_camera->wheelAction(1);
if (m_light.headlight)
updateLightPosition();
update();
}
else if (e->key() == Qt::Key_S)
{
emit m_camera->wheelAction(-1);
if (m_light.headlight)
updateLightPosition();
update();
}
else if (e->key() == Qt::Key_A)
{
emit m_camera->moveAction(QVector2D(0, -1));
if (m_light.headlight)
updateLightPosition();
update();
}
else if (e->key() == Qt::Key_D)
{
emit m_camera->moveAction(QVector2D(0, 1));
if (m_light.headlight)
updateLightPosition();
update();
}
else if (e->key() == Qt::Key_Escape)
{
parentWidget()->close();
}
else if (e->key() == Qt::Key_L)
{
updateLightPosition();
update();
}
}
void OglViewerWidget::keyReleaseEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_W || e->key() == Qt::Key_S)
{
emit m_camera->wheelAction(0);
if (m_light.headlight)
updateLightPosition();
update();
}
else if (e->key() == Qt::Key_A || e->key() == Qt::Key_D)
{
emit m_camera->moveAction(QVector2D(0, 0));
if (m_light.headlight)
updateLightPosition();
update();
}
}
void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e)
{
if (e->mimeData()->hasUrls())
@ -168,200 +335,57 @@ void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e)
void OglViewerWidget::dropEvent(QDropEvent * e)
{
emit loadFile(e->mimeData()->urls().first().toLocalFile());
}
void OglViewerWidget::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Space)
{
resetView();
}
else if (e->key() == Qt::Key_Escape)
{
parentWidget()->close();
}
else if (e->key() == Qt::Key_L)
{
updateLightPosition();
update();
}
else if (e->key() == Qt::Key_Minus)
{
m_zSpeed -= 0.1;
m_zSpeed < 0.09 ? m_zSpeed = 0 : NULL;
emit sendMessage(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
}
else if (e->key() == Qt::Key_Plus)
{
m_zSpeed += 0.1;
emit sendMessage(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
}
}
void OglViewerWidget::initializeGL()
{
initializeOpenGLFunctions();
//glClearColor(0.5000f, 0.8000f, 1.0000f, 0.0000f);
initShaders();
// Enable depth buffer
glEnable(GL_DEPTH_TEST);
// Enable back face culling
//glEnable(GL_CULL_FACE);
// Enable transparency
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_dataEngine = new GeometryEngine(this);
setConnections();
}
void OglViewerWidget::resizeGL(int w, int h)
{
// Calculate aspect ratio
qreal aspect = qreal(w) / qreal(h ? h : 1);
// Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
const qreal zNear = 0.1, zFar = 100.0, fov = 45.0;
// Reset projection
m_projection.setToIdentity();
// Set perspective projection
m_projection.perspective(fov, aspect, zNear, zFar);
}
void OglViewerWidget::paintGL()
{
if (m_lightOn && m_backgroundColorOn[3] == 1.0)
{
glClearColor(m_backgroundColorOn[0], m_backgroundColorOn[1], m_backgroundColorOn[2], 0.0000f);
m_backgroundColorOn[3] = 0.0;
}
else if(!m_lightOn && m_backgroundColorOff[3] == 1.0)
{
glClearColor(m_backgroundColorOff[0], m_backgroundColorOff[1], m_backgroundColorOff[2], 0.0000f);
m_backgroundColorOff[3] = 0.0;
}
// Clear color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Calculate model view transformation
QMatrix4x4 view;
view.translate(m_translation);
view.rotate(m_rotation);
// Set view-projection matrix
m_program.setUniformValue("vp_matrix", m_projection * view);
// Set Light values
m_program.setUniformValue("b_light", m_lightOn);
m_program.setUniformValue("light.position", m_light.position);
m_program.setUniformValue("light.intensities", m_light.intensities);
m_program.setUniformValue("light.attenuationFactor", m_light.attenuationFactor);
m_program.setUniformValue("light.ambientCoefficient", m_light.ambientCoefficient);
// Set camera position
QMatrix4x4 rotateBack;
rotateBack.rotate(m_rotation.inverted());
m_program.setUniformValue("cameraPosition", rotateBack * (-m_translation));
// Draw cube geometry
m_dataEngine->drawGeometry(&m_program, m_wireframe);
}
/////////////////////////////////////////////////////////////////////////
// private functions
void OglViewerWidget::initShaders()
{
// Compile vertex shader
if (!m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl"))
close();
// Compile fragment shader
if (!m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl"))
close();
// Link shader pipeline
if (!m_program.link())
close();
// Bind shader pipeline for use
if (!m_program.bind())
close();
}
void OglViewerWidget::setConnections()
{
connect(m_dataEngine, &GeometryEngine::requestResetView, this, &OglViewerWidget::resetView);
connect(parentWidget(), SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString)));
connect(this, SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString)));
connect(m_dataEngine, SIGNAL(sendMessage(QString, int)), parentWidget(), SLOT(printMessage(QString, int)));
connect(m_dataEngine, SIGNAL(requestUpdate()), this, SLOT(update()));
connect(m_dataEngine, SIGNAL(sendFileInfo(QString, QVector<Material>*, int, int)), parentWidget(), SLOT(setFileInfo(QString, QVector<Material>*, int, int)));
}
void OglViewerWidget::updateLightPosition()
{
QMatrix4x4 rotateBack;
rotateBack.rotate(m_rotation.inverted());
QVector3D cameraPosition = rotateBack * (-m_translation);
m_light.position.setX(cameraPosition.x());
m_light.position.setY(cameraPosition.y());
m_light.position.setZ(cameraPosition.z());
}
/////////////////////////////////////////////////////////////////////////
// private slots
void OglViewerWidget::resetView()
{
m_rotation = QQuaternion();
m_translation = { 0.0, 0.0, DEFAULT_Z_DISTANCE };
m_zSpeed = 1;
update();
m_dataEngine->loadFile(e->mimeData()->urls().first().toLocalFile());
}
/////////////////////////////////////////////////////////////////////////
// public slots
void OglViewerWidget::changeDirection(int direction)
void OglViewerWidget::loadFile(QString name)
{
switch (direction)
{
case 1:
m_rotDirections.x = !m_rotDirections.x;
break;
case 2:
m_rotDirections.y = !m_rotDirections.y;
break;
case 3:
m_rotDirections.z = !m_rotDirections.z;
break;
}
m_dataEngine->loadFile(name);
}
void OglViewerWidget::useFreeCamera()
{
delete m_camera;
m_camera = new FreeCamera;
if (m_lightOn)
updateLightPosition();
update();
}
void OglViewerWidget::useOrbitCamera()
{
delete m_camera;
m_camera = new OrbitCamera;
if (m_lightOn)
updateLightPosition();
update();
}
void OglViewerWidget::useMoveCamera()
{
delete m_camera;
m_camera = new MoveCamera;
if (m_lightOn)
updateLightPosition();
update();
}
void OglViewerWidget::toggleWireframe()
{
m_wireframe = 1 - m_wireframe;
m_wireframe = !m_wireframe;
update();
}
void OglViewerWidget::toggleLight()
{
m_lightOn = 1 - m_lightOn;
m_lightOn = !m_lightOn;
if (m_lightOn)
{
@ -372,6 +396,9 @@ void OglViewerWidget::toggleLight()
{
m_backgroundColorOff[3] = 1.0;
}
emit lightChanged(m_lightOn);
update();
}
@ -419,3 +446,20 @@ void OglViewerWidget::setAmbCoef(double value)
if (m_lightOn)
update();
}
void OglViewerWidget::setHeadlight(bool value)
{
m_light.headlight = value;
if (m_lightOn && value)
{
updateLightPosition();
update();
}
}
void OglViewerWidget::setBackfaceCulling(bool value)
{
m_backfaceCulling = value;
update();
}

View File

@ -0,0 +1,69 @@
#include "..\Header\OrbitCamera.h"
#include <QVector2D>
#include <qmath.h>
#include <iostream>
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
OrbitCamera::OrbitCamera()
{
resetView();
}
OrbitCamera::~OrbitCamera()
{
}
/////////////////////////////////////////////////////////////////////////
// functions
void OrbitCamera::rotateAction(QVector2D diff)
{
m_phi -= diff.x() * 0.01;
m_theta -= diff.y() * 0.01;
//m_theta = qMax(qMin(M_PI - 0.0001, m_theta), 0.0001);
}
void OrbitCamera::moveAction(QVector2D diff)
{
}
void OrbitCamera::wheelAction(double value)
{
m_roh -= m_zSpeed * value / 240;
m_roh = qMax(m_roh, 0.0);
}
void OrbitCamera::recalculateMatrix()
{
m_matrix = QMatrix4x4();
// different coordinate (spherical -> world) X->Z | Y->X | Z->Y
QVector3D tmpPosition(
qSin(m_theta) * qSin(m_phi),
qCos(m_theta),
qSin(m_theta) * qCos(m_phi)
);
QVector3D tmpRight(
qSin(m_phi - M_PI_2),
0,
qCos(m_phi - M_PI_2)
);
m_matrix.lookAt(m_roh * tmpPosition, QVector3D(0,0,0), QVector3D::crossProduct(tmpRight, tmpPosition));
}
void OrbitCamera::resetView()
{
m_roh = 4;
m_phi = 0;
m_theta = M_PI_2;
CameraInterface::resetView();
}

View File

@ -0,0 +1,222 @@
#include "..\Header\SettingsManager.h"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
SettingsManager::SettingsManager(QObject *parent)
: QObject(parent)
{
file.setFileName("meshviewer.config");
readFromFile();
}
SettingsManager::~SettingsManager()
{
writeToFile();
}
SettingsManager* SettingsManager::getInstance(QObject *parent)
{
static SettingsManager* instance = new SettingsManager(parent);
return instance;
}
/////////////////////////////////////////////////////////////////////////
// functions
void SettingsManager::readFromFile()
{
if (file.open(QIODevice::ReadOnly))
{
QByteArray stream = file.readAll();
QList<QByteArray> lines = stream.split('\n');
for (auto& it : lines)
{
if (it.startsWith("<bgOn>"))
{
QList<QByteArray> values = it.right(it.size() - it.indexOf('>') - 1).split(';');
for (int i = 0; i < 3; i++)
m_bgColorOn[i] = values[i].toFloat();
}
else if (it.startsWith("<bgOff>"))
{
QList<QByteArray> values = it.right(it.size() - it.indexOf('>') - 1).split(';');
for (int i = 0; i < 3; i++)
m_bgColorOff[i] = values[i].toFloat();
}
else if (it.startsWith("<liCo>"))
{
QList<QByteArray> values = it.right(it.size() - it.indexOf('>') - 1).split(';');
for (int i = 0; i < 3; i++)
m_lightColor[i] = values[i].toFloat();
}
else if (it.startsWith("<bfCul>"))
{
m_bfCulling = it.right(it.size() - it.indexOf('>') - 1).toInt();
}
else if (it.startsWith("<liOn>"))
{
m_light = it.right(it.size() - it.indexOf('>') - 1).toInt();
}
else if (it.startsWith("<heLi>"))
{
m_headlight = it.right(it.size() - it.indexOf('>') - 1).toInt();
}
else if (it.startsWith("<auCo>"))
{
m_autoColor = it.right(it.size() - it.indexOf('>') - 1).toInt();
}
else if (it.startsWith("<liTy>"))
{
m_lightType = it.right(it.size() - it.indexOf('>') - 1).toInt();
}
else if (it.startsWith("<atFa>"))
{
m_attenuation = it.right(it.size() - it.indexOf('>') - 1).toFloat();
}
else if (it.startsWith("<amCo>"))
{
m_ambient = it.right(it.size() - it.indexOf('>') - 1).toFloat();
}
}
file.close();
}
}
void SettingsManager::writeToFile()
{
file.open(QIODevice::WriteOnly);
file.write(QString("<bgOn>%1;%2;%3\n").arg(m_bgColorOn.x()).arg(m_bgColorOn.y()).arg(m_bgColorOn.z()).toUtf8());
file.write(QString("<bgOff>%1;%2;%3\n").arg(m_bgColorOff.x()).arg(m_bgColorOff.y()).arg(m_bgColorOff.z()).toUtf8());
file.write(QString("<liCo>%1;%2;%3\n").arg(m_lightColor.x()).arg(m_lightColor.y()).arg(m_lightColor.z()).toUtf8());
file.write(QString("<bfCul>%1\n").arg(m_bfCulling).toUtf8());
file.write(QString("<liOn>%1\n").arg(m_light).toUtf8());
file.write(QString("<heLi>%1\n").arg(m_headlight).toUtf8());
file.write(QString("<auCo>%1\n").arg(m_autoColor).toUtf8());
file.write(QString("<liTy>%1\n").arg(m_lightType).toUtf8());
file.write(QString("<atFa>%1\n").arg(m_attenuation).toUtf8());
file.write(QString("<amCo>%1\n").arg(m_ambient).toUtf8());
file.close();
}
// getter ///////////////////////////////////////////////////////////////
QVector3D SettingsManager::getBgColorOn() const
{
return m_bgColorOn;
}
QVector3D SettingsManager::getBgColorOff() const
{
return m_bgColorOff;
}
bool SettingsManager::isBfCulling() const
{
return m_bfCulling;
}
bool SettingsManager::isLight() const
{
return m_light;
}
int SettingsManager::getLightType() const
{
return m_lightType;
}
QVector3D SettingsManager::getLightColor() const
{
return m_lightColor;
}
float SettingsManager::getAttenuation() const
{
return m_attenuation;
}
float SettingsManager::getAmbient() const
{
return m_ambient;
}
bool SettingsManager::isHeadlight() const
{
return m_headlight;
}
bool SettingsManager::isAutoColor() const
{
return m_autoColor;
}
/////////////////////////////////////////////////////////////////////////
// slots
void SettingsManager::setBgColorOn(QVector3D value)
{
m_bgColorOn = value;
}
void SettingsManager::setBgColorOff(QVector3D value)
{
m_bgColorOff = value;
}
void SettingsManager::setBfCulling(bool value)
{
m_bfCulling = value;
}
void SettingsManager::setLight(bool value)
{
m_light = value;
}
void SettingsManager::setLightType(int value)
{
m_lightType = value;
}
void SettingsManager::setLightColor(QVector3D value)
{
m_lightColor = value;
}
void SettingsManager::setAttenuation(double value)
{
m_attenuation = value;
}
void SettingsManager::setAmbient(double value)
{
m_ambient = value;
}
void SettingsManager::setHeadlight(bool value)
{
m_headlight = value;
}
void SettingsManager::setAutoColor(int value)
{
if (value == 0)
m_autoColor = false;
else
m_autoColor = true;
}

View File

@ -1,5 +1,9 @@
#include "..\Header\SettingsWindow.h"
#include <QString>
#include "..\Header\SettingsManager.h"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
SettingsWindow::SettingsWindow(QWidget * parent)
: QWidget(parent)
@ -9,50 +13,45 @@ SettingsWindow::SettingsWindow(QWidget * parent)
setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
// 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_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
setupConnections();
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_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
// set default values
SettingsManager* sm = SettingsManager::getInstance(this);
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_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
ui->lightOff_R_SB->setValue((int)(sm->getBgColorOff()[0]));
ui->lightOff_G_SB->setValue((int)(sm->getBgColorOff()[1]));
ui->lightOff_B_SB->setValue((int)(sm->getBgColorOff()[2]));
// 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_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
ui->lightOn_R_SB->setValue((int)(sm->getBgColorOn()[0]));
ui->lightOn_G_SB->setValue((int)(sm->getBgColorOn()[1]));
ui->lightOn_B_SB->setValue((int)(sm->getBgColorOn()[2]));
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_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
ui->light_R_SB->setValue((int)(sm->getLightColor()[0]));
ui->light_G_SB->setValue((int)(sm->getLightColor()[1]));
ui->light_B_SB->setValue((int)(sm->getLightColor()[2]));
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_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
ui->ambCoef->setValue(sm->getAmbient());
ui->attFac->setValue(sm->getAttenuation());
// 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_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged);
ui->checkBackfaceCulling->setChecked(sm->isBfCulling());
ui->checkAutoColor->setChecked(sm->isAutoColor());
ui->checkHeadlight->setChecked(sm->isHeadlight());
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_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged);
if (sm->getLightType() == 1)
ui->radioDirectLight->setChecked(true);
else
ui->radioPointLight->setChecked(true);
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_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged);
connect(this, &SettingsWindow::updateBGColorOff, sm, &SettingsManager::setBgColorOff);
connect(this, &SettingsWindow::updateBGColorOn, sm, &SettingsManager::setBgColorOn);
connect(this, &SettingsWindow::updateLightColor, sm, &SettingsManager::setLightColor);
connect(this, &SettingsWindow::updateAttFac, sm, &SettingsManager::setAttenuation);
connect(this, &SettingsWindow::updateAmbCoef, sm, &SettingsManager::setAmbient);
connect(this, &SettingsWindow::sendHeadlight, sm, &SettingsManager::setHeadlight);
connect(this, &SettingsWindow::sendBackfaceCulling, sm, &SettingsManager::setBfCulling);
connect(ui->checkAutoColor, &QCheckBox::stateChanged, sm, &SettingsManager::setAutoColor);
connect(this, &SettingsWindow::changeLightType, sm, &SettingsManager::setLightType);
connect(ui->checkAutoColor, &QCheckBox::toggled, this, &SettingsWindow::autoColorToggled);
connect(ui->radioDirectLight, &QRadioButton::toggled, this, &SettingsWindow::radioToggled);
connect(ui->ambCoef, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAmbCoef(value); });
connect(ui->attFac, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAttFac(value); });
}
SettingsWindow::~SettingsWindow()
@ -60,50 +59,104 @@ SettingsWindow::~SettingsWindow()
delete ui;
}
////////////////////////////////////////////////////////////////////////////////
// connection slots
/////////////////////////////////////////////////////////////////////////
// functions
void SettingsWindow::setupConnections()
{
// light off
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_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_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_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_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_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_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_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_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);
connect(ui->checkAutoColor, &QCheckBox::toggled, this, &SettingsWindow::autoColorToggled);
connect(ui->radioDirectLight, &QRadioButton::toggled, this, &SettingsWindow::radioToggled);
connect(ui->ambCoef, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAmbCoef(value); });
connect(ui->attFac, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAttFac(value); });
connect(ui->checkBackfaceCulling, &QCheckBox::toggled, [this]() {emit sendBackfaceCulling(ui->checkBackfaceCulling->isChecked()); });
connect(ui->spinZSpeed, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int value) {emit sendZommSpeed(value); });
connect(ui->checkHeadlight, &QCheckBox::toggled, [this]() {emit sendHeadlight(ui->checkHeadlight->isChecked()); });
}
/////////////////////////////////////////////////////////////////////////
// slots
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);
emit changeLightType(1);
}
else
{
ui->attFac->setEnabled(true);
ui->ambCoef->setEnabled(true);
emit changeLightType(2);
}
}
@ -120,5 +173,11 @@ 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));
}
}

View File

@ -1,8 +1,6 @@
#include "Header\MainWindow.h"
#include <QtWidgets/QApplication>
// TODO: add glow/emissive
int main(int argc, char *argv[])
{
QApplication a(argc, argv);

View File

@ -1,3 +1,12 @@
https://git.rwth-aachen.de/carstenf/OpenGL
Pulled from here as backup of work that I did under the develop branch. I hope to come back to this and port to Python using this as a reference for logic and how-to.
Below is original README text.
# MshViewer
I started to learn OpenGL. Therefore i decided to implement a .msh viewer for SWBFII assets, since the old one
@ -12,10 +21,4 @@ So far it is just me. If you wanna help me, let me know :D
Feel free to use my code the way you like. But remember i used some public libraries. Make sure you read their
licence, too.
### To Do
- normal map,
- list all msh in a directory
- glow/emissive
- optional display bones, shadow, collision
- change pose
- animation

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,14 +0,0 @@
#version 450 core
// Input
in vec2 UV;
// Ouput data
out vec3 color;
uniform sampler2D textureSampler;
void main()
{
color = texture(textureSampler, UV).rgb;
}

View File

@ -1,20 +0,0 @@
#version 450 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;
// Output
out vec2 UV;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace, 1);
UV = vertexUV;
}

Binary file not shown.

Binary file not shown.

BIN
preview.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB