59 Commits

Author SHA1 Message Date
Anakin
54b87b5de7 fixed things i've broken by the merge conflict 2017-06-20 11:58:03 +02:00
Anakin
68387fe7a7 Merge branch 'developement_1' of git.rwth-aachen.de:carstenf/OpenGL into developement_1
# Conflicts:
#	QtMeshViewer/Header/MainWindow.h
#	QtMeshViewer/Source/MainWindow.cpp
2017-06-20 11:45:15 +02:00
Anakin
44732057b6 using signal slot to update the combobox entries 2017-06-20 11:41:10 +02:00
2d34492517 Implemented qtreeviewwidget instead of a list 2017-06-18 09:33:02 -05:00
3f2713bd16 Fixed logic issue with offset file to file name in listWidget. Edited feel of settings window a bit 2017-06-18 06:46:45 -05:00
c2f7118ed6 Implemented recursive scan for mesh files on selection of dir path. Setup name instead of full path in list. 2017-06-18 06:17:40 -05:00
c6d82f5f55 Updated Settings to cleanup logic plus add a note for hard coded paths. 2017-06-18 06:14:10 -05:00
Anakin
33fafb29a8 removed unused or useless stuff,
renamed some functions for better description,
repaired the SettingsManager usage,
ToDo:
Dropdown list is not updated, it needs a restart,
display names for the directories instead of the path,
2017-06-17 15:42:43 +02:00
6141263f45 Edited open() function to be more descriptive. Set to openFileActual 2017-06-17 05:18:21 -05:00
e59dd980bd Temp update to show unexpected segfault error 2017-06-16 03:16:30 -05:00
1e71ebed47 Set ability to fill listWidget in SettingsWindow with saved dir list from SettingsManager. 2017-06-15 23:28:53 -05:00
d908894265 Added add and remove functionality to settings listWidget 2017-06-15 22:31:11 -05:00
Maxim Stewart
bddc7ea852 Getting dir list to the drop down field 2017-05-31 03:10:34 -05:00
Maxim Stewart
0372a4ad8c Setting up removing and adding stuff to the settings window dirlistview 2017-05-31 03:09:32 -05:00
Maxim Stewart
e768ae9af8 Setup dirList access from settings through getter and setters 2017-05-30 21:38:51 -05:00
Maxim Stewart
b089fcdaf6 Added settings for getting drop down filled and set list to hide folders.
Need to make a dirList setter plus get settings window to keep dirList for editing.
2017-05-30 21:37:17 -05:00
Maxim Stewart
cdda1922fa Fixed accidental overload of function. 2017-05-30 07:49:54 -05:00
Maxim Stewart
031c620f52 Added filter to QFileSystemModel fmodel
Setup some comments regarding a setFilter part
Edited getAssetLibrary to pass arguments to setAsset -- Note will be used for dropdown interaction.
Set a temp path for testing purposes.
2017-05-30 07:42:14 -05:00
Maxim Stewart
7a41f2d9bf Added QFileSystemModel for the fileListView or aka treeView
Added QString filters to be used with QFileSystemModel
Added setAsset method as part of getAssetLibrary for reusability
2017-05-30 07:38:19 -05:00
Maxim Stewart
b2efa83e17 Added check for qkList in meshviewer.config
Added QString listOfDirs
Added gettter method to get listOfDirs
Edited MainWindow.ui to prepare for list of file plus dir drop down
2017-05-30 07:12:50 -05: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 2419 additions and 2714 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"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property> </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>600</width> <width>800</width>
<height>400</height> <height>600</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@@ -19,7 +19,9 @@
<property name="windowTitle"> <property name="windowTitle">
<string>MainWindow</string> <string>MainWindow</string>
</property> </property>
<widget class="QWidget" name="centralWidget"/> <widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
<widget class="QToolBar" name="mainToolBar"> <widget class="QToolBar" name="mainToolBar">
<property name="allowedAreas"> <property name="allowedAreas">
<set>Qt::LeftToolBarArea|Qt::RightToolBarArea|Qt::TopToolBarArea</set> <set>Qt::LeftToolBarArea|Qt::RightToolBarArea|Qt::TopToolBarArea</set>
@@ -32,10 +34,68 @@
</attribute> </attribute>
</widget> </widget>
<widget class="QStatusBar" name="statusBar"/> <widget class="QStatusBar" name="statusBar"/>
<widget class="QDockWidget" name="dockWidget">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="floating">
<bool>false</bool>
</property>
<property name="features">
<set>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>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QComboBox" name="dirDropDownList">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="fileTreeWidget">
<property name="autoExpandDelay">
<number>0</number>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources> <resources/>
<include location="../Resources/Resources.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@@ -6,22 +6,22 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>584</width>
<height>300</height> <height>645</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Settings</string> <string>Settings</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="1" column="0">
<widget class="QGroupBox" name="groupBackground"> <widget class="QGroupBox" name="groupBackground">
<property name="title"> <property name="title">
<string>Background</string> <string>Background</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="5"> <item row="4" column="5">
<widget class="QLineEdit" name="lightOn_G_LE"> <widget class="QSpinBox" name="lightOn_G_SB">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
@@ -31,8 +31,11 @@
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="text"> <property name="buttonSymbols">
<string>5</string> <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -86,7 +89,7 @@
</widget> </widget>
</item> </item>
<item row="4" column="8"> <item row="4" column="8">
<widget class="QLineEdit" name="lightOn_B_LE"> <widget class="QSpinBox" name="lightOn_B_SB">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
@@ -96,8 +99,11 @@
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="text"> <property name="buttonSymbols">
<string>5</string> <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -123,28 +129,34 @@
</widget> </widget>
</item> </item>
<item row="2" column="5"> <item row="2" column="5">
<widget class="QLineEdit" name="lightOff_G_LE"> <widget class="QSpinBox" name="lightOff_G_SB">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>30</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="text"> <property name="buttonSymbols">
<string>204</string> <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="8"> <item row="2" column="8">
<widget class="QLineEdit" name="lightOff_B_LE"> <widget class="QSpinBox" name="lightOff_B_SB">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>30</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="text"> <property name="buttonSymbols">
<string>255</string> <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -162,7 +174,7 @@
</widget> </widget>
</item> </item>
<item row="2" column="2"> <item row="2" column="2">
<widget class="QLineEdit" name="lightOff_R_LE"> <widget class="QSpinBox" name="lightOff_R_SB">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -172,8 +184,11 @@
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="text"> <property name="buttonSymbols">
<string>127</string> <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -225,7 +240,7 @@
</widget> </widget>
</item> </item>
<item row="4" column="2"> <item row="4" column="2">
<widget class="QLineEdit" name="lightOn_R_LE"> <widget class="QSpinBox" name="lightOn_R_SB">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
@@ -235,8 +250,11 @@
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
<property name="text"> <property name="buttonSymbols">
<string>5</string> <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -263,23 +281,10 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QGroupBox" name="groupLight"> <widget class="QGroupBox" name="groupLight">
<property name="title"> <property name="title">
<string>Light</string> <string>Light</string>
@@ -292,109 +297,6 @@
</property> </property>
</widget> </widget>
</item> </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="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>B:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLineEdit" name="light_G_LE">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>255</string>
</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>
<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>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QLineEdit" name="light_B_LE">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>255</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>R:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSlider" name="light_R_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="1" column="8">
<widget class="QSlider" name="light_B_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="1" column="5"> <item row="1" column="5">
<widget class="QSlider" name="light_G_S"> <widget class="QSlider" name="light_G_S">
<property name="maximum"> <property name="maximum">
@@ -408,42 +310,10 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="4">
<spacer name="verticalSpacerLight">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="attFac">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="2" column="4" colspan="2"> <item row="2" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="ambCoef"> <widget class="QDoubleSpinBox" name="ambCoef">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
@@ -465,13 +335,235 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="4" colspan="4"> <item row="3" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="attFac">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>R:</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>
</property>
</widget>
</item>
<item row="1" column="8">
<widget class="QSlider" name="light_B_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="1" column="1">
<widget class="QSpinBox" name="light_R_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="0" column="4" colspan="3">
<widget class="QRadioButton" name="radioPointLight"> <widget class="QRadioButton" name="radioPointLight">
<property name="text"> <property name="text">
<string>Point light</string> <string>Point light</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2">
<widget class="QSlider" name="light_R_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="1" column="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QSpinBox" name="light_G_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</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="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>B:</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QSpinBox" name="light_B_SB">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="0" column="7" colspan="2">
<widget class="QCheckBox" name="checkHeadlight">
<property name="text">
<string>Headlight</string>
</property>
</widget>
</item>
</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="0" column="3" colspan="3">
<widget class="QCheckBox" name="checkBackfaceCulling">
<property name="text">
<string>Backface Culling</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="labelZoomSpeed">
<property name="text">
<string>Zoom speed:</string>
</property>
</widget>
</item>
<item row="1" column="6">
<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="5">
<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="2" column="3" colspan="4">
<widget class="QLabel" name="label">
<property name="text">
<string>Directory Drop Down List:</string>
</property>
</widget>
</item>
<item row="4" column="3" colspan="4">
<widget class="QListWidget" name="dirListWidget"/>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_9">
<property name="text">
<string>*** &quot;BF1_ModTools&quot; Goes To &quot;C:/BF1_ModTools/Assets/Shipped Worlds/&quot;
&quot;BF2_ModTools&quot; Goes To &quot;C:/BF2_ModTools/assets/Sides/&quot;</string>
</property>
</widget>
</item>
<item row="5" column="5">
<widget class="QPushButton" name="removeItem">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QPushButton" name="addItem">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

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 #pragma once
#include <QWidget> #include <QWidget>
#include <QString>
#include "ui_FileInfoWindow.h" #include "ui_FileInfoWindow.h"
class FileInfoWindow : public QWidget class FileInfoWindow : public QWidget
@@ -8,13 +7,21 @@ class FileInfoWindow : public QWidget
Q_OBJECT Q_OBJECT
public: public:
FileInfoWindow(QWidget *parent = Q_NULLPTR); FileInfoWindow(QWidget *parent = Q_NULLPTR)
~FileInfoWindow(); : 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: private:
Ui::FileInfoWindow* ui; Ui::FileInfoWindow* ui;
public: public:
void setBasicText(QString text); void setBasicText(QString text) { ui->basic->setText(text); };
void setDetailText(QString text); void setDetailText(QString text) { ui->detail->setText(text); };
}; };

View File

@@ -1,17 +1,11 @@
#pragma once #pragma once
#include <fstream> #include <QOpenGlTexture>
#include <QFile>
#include <QVector> #include <QVector>
#include <QVector2D> #include <QVector2D>
#include <QVector3D>
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QQuaternion> #include <QQuaternion>
#include <QOpenGLFunctions>
#include <QOpenGlTexture>
#include <QObject>
#include <QOpenGLTexture>
#include <QRegExp> #include <QRegExp>
#include <..\Header\MainWindow.h>
struct BoundingBox { struct BoundingBox {
QQuaternion rotation; QQuaternion rotation;
@@ -24,20 +18,23 @@ struct VertexData
QVector3D position; QVector3D position;
QVector2D texCoord; QVector2D texCoord;
QVector3D vertexNormal; QVector3D vertexNormal;
QVector3D polygonNormal;
QVector3D tangent;
QVector3D bitangent;
}; };
struct Segment { struct Segment {
std::uint32_t textureIndex = 0; quint32 textureIndex = 0;
QVector<VertexData> vertices; QVector<VertexData> vertices;
QVector<GLuint> indices; QVector<GLuint> indices;
}; };
struct Model { struct Model {
std::string name = ""; QString name = "";
std::string parent = ""; QString parent = "";
QMatrix4x4 m4x4Translation; QMatrix4x4 m4x4Translation;
QQuaternion quadRotation; QQuaternion quadRotation;
std::vector<Segment*> segmList; QVector<Segment*> segmList;
}; };
struct Material { struct Material {
@@ -48,36 +45,30 @@ struct Material {
QString tx3d; QString tx3d;
QOpenGLTexture* texture0 = Q_NULLPTR; QOpenGLTexture* texture0 = Q_NULLPTR;
QOpenGLTexture* texture1 = 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 diffuseColor = { 1.0, 0.0, 0.0, 1.0 };
QVector4D ambientColor = { 1.0, 1.0, 1.0, 1.0 }; QVector4D ambientColor = { 1.0, 1.0, 1.0, 1.0 };
float shininess = 80; float shininess = 1;
bool flags[8] = { false }; bool flags[8] = { false };
bool transparent = false; bool transparent = false;
std::uint8_t rendertype = 0; quint8 rendertype = 0;
std::uint8_t dataValues[2] = { 0 }; quint8 dataValues[2] = { 0 };
}; };
class FileInterface : public QObject class FileInterface
{ {
Q_OBJECT
public: public:
explicit FileInterface(QString path, QObject *parent) explicit FileInterface(QString path)
: QObject(parent) : m_models(new QVector<Model*>)
, m_models(new QVector<Model*>)
, m_materials(new QVector<Material>) , m_materials(new QVector<Material>)
{ {
//open file //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()); 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("/|\\\\"))); m_filepath = path.left(path.lastIndexOf(QRegExp("/|\\\\")));
}; };
@@ -106,7 +97,7 @@ public:
protected: protected:
QVector<Model*>* m_models; QVector<Model*>* m_models;
std::fstream m_file; QFile m_file;
QVector<Material>* m_materials; QVector<Material>* m_materials;
BoundingBox m_sceneBbox; BoundingBox m_sceneBbox;
QString m_filepath; QString m_filepath;
@@ -142,6 +133,4 @@ public:
return defMaterial; 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 #pragma once
#include "..\Header\FileInterface.h"
#include <QObject> #include <QObject>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QVector> #include <QVector>
#include "FileInterface.h"
struct DrawInformation { struct DrawInformation {
unsigned int offset; unsigned int offset;
@@ -22,24 +22,27 @@ public:
GeometryEngine(QObject *parent = Q_NULLPTR); GeometryEngine(QObject *parent = Q_NULLPTR);
virtual ~GeometryEngine(); virtual ~GeometryEngine();
// attributes
private: private:
QOpenGLBuffer m_arrayBuf; QOpenGLBuffer m_arrayBuf;
QOpenGLBuffer m_indexBuf; QOpenGLBuffer m_indexBuf;
QVector<Material>* m_materials = Q_NULLPTR; QVector<Material>* m_materials = Q_NULLPTR;
QVector<DrawInformation> m_drawList;
BoundingBox m_boundings;
Material* m_defaultMaterial; Material* m_defaultMaterial;
BoundingBox m_boundings;
QVector<DrawInformation> m_drawList;
// functions
private:
void clearData(); void clearData();
void setupPipeline(QOpenGLShaderProgram * program);
public slots: public:
void drawGeometry(QOpenGLShaderProgram *program);
void loadFile(QString filePath); void loadFile(QString filePath);
void drawGeometry(QOpenGLShaderProgram *program, bool wireframe);
// signals
signals: signals:
void requestResetView(); void requestResetView();
void sendMessage(QString message, int severity);
void requestUpdate(); void requestUpdate();
void sendFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle);
}; };

View File

@@ -1,12 +1,10 @@
#pragma once #pragma once
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
#include <qwidget.h> #include <QWidget>
#include <QByteArray>
#include <QStringList>
#include <QLabel>
#include "ui_MainWindow.h" #include "ui_MainWindow.h"
#include "..\Header\FileInfoWindow.h" #include "FileInfoWindow.h"
#include <QByteArray>
#include <QLabel>
struct Material; struct Material;
@@ -18,27 +16,41 @@ public:
MainWindow(QWidget *parent = Q_NULLPTR); MainWindow(QWidget *parent = Q_NULLPTR);
~MainWindow(); ~MainWindow();
// attributes
private: private:
Ui::MainWindowClass* ui; Ui::MainWindowClass* ui;
int m_curSeverity;
void setupWidgets();
QByteArray m_fileInfo; QByteArray m_fileInfo;
QLabel* m_output; QLabel* m_output;
FileInfoWindow* m_infoWindow; int m_curSeverity;
FileInfoWindow* m_infoWindow;
QStringList m_filters;
// functions
private: private:
void openFile(); void setupWidgets();
void aboutFile(); void updateAssetTree(QString);
void aboutTool(); void openFileDialog();
void openFile(QString);
void takeScreenShot(); void takeScreenShot();
void aboutTool();
protected: protected:
virtual void resizeEvent(QResizeEvent * e) Q_DECL_OVERRIDE; virtual void resizeEvent(QResizeEvent * e) Q_DECL_OVERRIDE;
// slots
public slots: public slots:
void printMessage(QString message, int severity); void printMessage(QString message, int severity);
void setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle); void setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle);
// private slots
private slots:
void setupAssetLibrary();
void on_fileTreeWidget_doubleClicked();
void on_dirDropDownList_currentTextChanged(const QString &arg1);
// signals
signals: signals:
void loadFile(QString); 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 #pragma once
#include "..\Header\FileInterface.h" #include "..\Header\FileInterface.h"
#include <QList>
struct ChunkHeader { struct ChunkHeader {
char name[5]; QString name;
std::uint32_t size; quint32 size;
std::streampos position; qint64 position;
}; };
enum ModelTyp { enum ModelTyp {
@@ -20,7 +20,7 @@ enum ModelTyp {
class MshFile : public FileInterface class MshFile : public FileInterface
{ {
public: public:
explicit MshFile(QString path, QObject *parent = Q_NULLPTR); explicit MshFile(QString path);
virtual ~MshFile(); virtual ~MshFile();
private: private:
@@ -29,22 +29,22 @@ private:
virtual void import() Q_DECL_OVERRIDE Q_DECL_FINAL; 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 analyseModlChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void analyseGeomChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList); void analyseGeomChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void analyseSegmChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList); void analyseSegmChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void analyseClthChunks(Model* dataDestination, std::list<ChunkHeader*> &chunkList); void analyseClthChunks(Model* dataDestination, QList<ChunkHeader*> &chunkList);
void readVertex(Segment* dataDestination, std::streampos position); void readVertex(Segment* dataDestination, qint64 position);
void readUV(Segment* dataDestination, std::streampos position); void readUV(Segment* dataDestination, qint64 position);
void loadTexture(QOpenGLTexture*& destination, QString filepath, QString& filename); void loadTexture(QOpenGLTexture*& destination, QString filepath, QString& filename);
QMatrix4x4 getParentMatrix(std::string parent) const; QMatrix4x4 getParentMatrix(QString parent) const;
QQuaternion getParentRotation(std::string parent) const; QQuaternion getParentRotation(QString parent) const;
}; };

View File

@@ -1,14 +1,11 @@
#pragma once #pragma once
#include "geometryengine.h"
#include "..\Header\SettingsWindow.h"
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QMatrix4x4>
#include <QQuaternion>
#include <QVector2D>
#include <QBasicTimer>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QMatrix4x4>
#include "GeometryEngine.h"
#include "SettingsWindow.h"
#include "CameraInterface.h"
class GeometryEngine; class GeometryEngine;
@@ -21,79 +18,82 @@ public:
explicit OglViewerWidget(QWidget *parent = 0); explicit OglViewerWidget(QWidget *parent = 0);
~OglViewerWidget(); ~OglViewerWidget();
signals: // attributes
void loadFile(QString);
private: 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 { struct {
bool left = false; bool left = false;
bool right = false; bool right = false;
QVector2D position; QVector2D position;
} m_mouse; } m_mouse;
struct { QMatrix4x4 m_projection;
bool x = true; CameraInterface* m_camera;
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;
SettingsWindow* m_settings; SettingsWindow* m_settings;
QVector4D m_backgroundColorOn = {0.02f, 0.02f, 0.02f, 1.0f}; // functions
QVector4D m_backgroundColorOff = { 0.5f, 0.8f, 1.0f, 1.0f }; private:
void setDefaultValues();
QOpenGLShaderProgram m_program; void initShaders();
GeometryEngine *m_dataEngine; void resetView();
void updateLightPosition();
QMatrix4x4 m_projection;
QVector3D m_translation;
QQuaternion m_rotation;
bool m_wireframe = false;
bool m_lightOn = false;
double m_zSpeed = 1.0;
protected: 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 initializeGL() Q_DECL_OVERRIDE;
void resizeGL(int w, int h) Q_DECL_OVERRIDE; void resizeGL(int w, int h) Q_DECL_OVERRIDE;
void paintGL() Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE;
private: void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void initShaders(); void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void setConnections(); void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void updateLightPosition(); void wheelEvent(QWheelEvent *e) Q_DECL_OVERRIDE;
private slots: void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE;
void resetView(); void keyReleaseEvent(QKeyEvent *e) Q_DECL_OVERRIDE;
void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE;
// slots
public slots: public slots:
void changeDirection(int direction); void loadFile(QString name);
void useFreeCamera();
void useOrbitCamera();
void useMoveCamera();
void toggleWireframe(); void toggleWireframe();
void toggleLight(); void toggleLight();
void showSettings(); void showSettings();
void setBGColorOff(QVector3D value); void setBGColorOff(QVector3D value);
void setBGColorOn(QVector3D value); void setBGColorOn(QVector3D value);
void setLightColor(QVector3D value); void setLightColor(QVector3D value);
void setAttFac(double value); void setAttFac(double value);
void setAmbCoef(double value); void setAmbCoef(double value);
void setHeadlight(bool value);
void setBackfaceCulling(bool value);
// signals
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,79 @@
#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 m_file;
QStringList m_listOfDirs;
QVector3D m_bgColorOn = { 5, 5, 5 };
QVector3D m_bgColorOff = { 128, 204, 255 };
QVector3D m_lightColor = { 255,255,255 };
bool m_bfCulling = false;
bool m_light = false;
bool m_headlight = false;
bool m_autoColor = true;
float m_attenuation = 0.0f;
float m_ambient = 0.005f;
int m_lightType = 1; // 1 = direct, 2 = point
// functions
private:
void readFromFile();
void writeToFile();
public:
QVector3D getBgColorOn() const;
QVector3D getBgColorOff() const;
bool isBfCulling() const;
bool isLight() const;
QStringList getListOfDirs();
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);
void updateDirectories(QString path);
// signals
signals:
void dirsChanged();
};

View File

@@ -3,6 +3,7 @@
#include "ui_SettingsWindow.h" #include "ui_SettingsWindow.h"
#include <QVector3D> #include <QVector3D>
class SettingsWindow : public QWidget class SettingsWindow : public QWidget
{ {
Q_OBJECT Q_OBJECT
@@ -14,6 +15,8 @@ public:
private: private:
Ui::SettingsWindow* ui; Ui::SettingsWindow* ui;
void setupConnections();
private slots: private slots:
void autoColorToggled(); void autoColorToggled();
void radioToggled(); void radioToggled();
@@ -21,10 +24,19 @@ private slots:
void backgroundColorOnChanged(); void backgroundColorOnChanged();
void lightColorChanged(); void lightColorChanged();
void on_addItem_clicked();
void on_removeItem_clicked();
signals: signals:
void updateBGColorOff(QVector3D value); void updateBGColorOff(QVector3D value);
void updateBGColorOn(QVector3D value); void updateBGColorOn(QVector3D value);
void updateLightColor(QVector3D value); void updateLightColor(QVector3D value);
void updateAttFac(double value); void updateAttFac(double value);
void updateAmbCoef(double value); void updateAmbCoef(double value);
void sendHeadlight(bool value);
void sendBackfaceCulling(bool value);
void sendZommSpeed(int percent);
void changeLightType(int value);
void pathChanged(QString path);
}; };

View File

@@ -1,39 +1,38 @@
#pragma once #pragma once
#include <fstream> #include "OutputDevice.h"
#include <QImage> #include <QImage>
#include <QColor> #include <QColor>
#include <QVector>
#include <QFile>
#include <iostream>
QImage loadTga(QString filePath, bool &success) QImage loadTga(QString filePath, bool &success)
{ {
QImage img; 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 // read in the header
std::uint8_t ui8x18Header[19] = { 0 }; quint8 ui8x18Header[19] = { 0 };
fsPicture.read(reinterpret_cast<char*>(&ui8x18Header), sizeof(ui8x18Header) - 1); file.read(reinterpret_cast<char*>(&ui8x18Header), sizeof(ui8x18Header) - 1);
//get variables //get variables
std::uint32_t ui32BpP; quint32 ui32BpP;
std::uint32_t ui32Width; quint32 ui32Width;
std::uint32_t ui32Height; quint32 ui32Height;
std::uint32_t ui32IDLength; quint32 ui32IDLength;
std::uint32_t ui32PicType; quint32 ui32PicType;
std::uint32_t ui32PaletteLength; quint32 ui32PaletteLength;
std::uint32_t ui32Size; quint32 ui32Size;
// extract all information from header // extract all information from header
ui32IDLength = ui8x18Header[0]; ui32IDLength = ui8x18Header[0];
@@ -47,57 +46,49 @@ QImage loadTga(QString filePath, bool &success)
ui32Size = ui32Width * ui32Height * ui32BpP / 8; ui32Size = ui32Width * ui32Height * ui32BpP / 8;
// jump to the data block // jump to the data block
fsPicture.seekg(ui32IDLength + ui32PaletteLength, std::ios_base::cur); file.seek(ui32IDLength + ui32PaletteLength + 18);
img = QImage(ui32Width, ui32Height, ui32BpP == 32? QImage::Format_RGBA8888 : QImage::Format_RGB888);
// uncompressed // uncompressed
if (ui32PicType == 2 && (ui32BpP == 24 || ui32BpP == 32)) if (ui32PicType == 2 && (ui32BpP == 24 || ui32BpP == 32))
{ {
std::vector<std::uint8_t> vui8Pixels; img = QImage(ui32Width, ui32Height, ui32BpP == 32 ? QImage::Format_RGBA8888 : QImage::Format_RGB888);
vui8Pixels.resize(ui32Size); int lineWidth = ui32Width * ui32BpP / 8;
fsPicture.read(reinterpret_cast<char*>(vui8Pixels.data()), ui32Size);
for (unsigned int y = 0; y < ui32Height; y++) for (int i = ui32Height - 1; i >= 0; --i)
{ file.read(reinterpret_cast<char*>(img.scanLine(i)), lineWidth);
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);
QColor value(valr, valg, valb);
img.setPixelColor(x, ui32Width - 1 - y, value);
}
}
} }
// else if compressed 24 or 32 bit // else if compressed 24 or 32 bit
else if (ui32PicType == 10 && (ui32BpP == 24 || ui32BpP == 32)) // compressed else if (ui32PicType == 10 && (ui32BpP == 24 || ui32BpP == 32)) // compressed
{ {
std::uint8_t tempChunkHeader; OutputDevice::getInstance()->print("compressed tga is not supported by SWBF", 1);
std::uint8_t tempData[5];
img = QImage(ui32Width, ui32Height, QImage::Format_RGBA8888);
quint8 tempChunkHeader;
quint8 tempData[5];
unsigned int tmp_pixelIndex = 0; unsigned int tmp_pixelIndex = 0;
do { do {
fsPicture.read(reinterpret_cast<char*>(&tempChunkHeader), sizeof(tempChunkHeader)); file.read(reinterpret_cast<char*>(&tempChunkHeader), sizeof(tempChunkHeader));
if (tempChunkHeader >> 7) // repeat count if (tempChunkHeader >> 7) // repeat count
{ {
// just use the first 7 bits // 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++) for (int i = 0; i <= tempChunkHeader; i++)
{ {
QColor color; QColor color;
if (ui32BpP == 32) 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 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++; tmp_pixelIndex++;
} }
} }
@@ -108,16 +99,16 @@ QImage loadTga(QString filePath, bool &success)
for (int i = 0; i <= tempChunkHeader; i++) 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; QColor color;
if (ui32BpP == 32) 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 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++; tmp_pixelIndex++;
} }
} }
@@ -126,15 +117,12 @@ QImage loadTga(QString filePath, bool &success)
// not useable format // not useable format
else else
{ {
fsPicture.close();
img = QImage(1, 1, QImage::Format_RGB32);
img.fill(Qt::red);
success = false; 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>info.png</file>
<file>about.png</file> <file>about.png</file>
<file>open.png</file> <file>open.png</file>
<file>X.png</file>
<file>Y.png</file>
<file>Z.png</file>
<file>screenshot.png</file> <file>screenshot.png</file>
<file>wireframe.png</file> <file>wireframe.png</file>
<file>light_off.png</file> <file>light_off.png</file>
<file>light_on.png</file> <file>light_on.png</file>
<file>solid.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>settings.png</file>
<file>freeCamera.png</file>
<file>orbitalCamera.png</file>
<file>walkCamera.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

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

View File

@@ -4,11 +4,23 @@ source code: https://git.rwth-aachen.de/carstenf/OpenGL/tree/master/QtMeshViewer
=============================================================== ===============================================================
Controll: Controll:
Free Camera: static view position and you rotate and move the object
left mouse - rotate left mouse - rotate
right mouse - move right mouse - move
scroll - zoom 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 space - reset view
+/- - adjust zoom speed
L - set light to current position L - set light to current position
esc - close esc - close

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

View File

@@ -4,16 +4,22 @@ precision mediump int;
precision mediump float; precision mediump float;
#endif #endif
uniform mat3 n_matrix; uniform mat3 normalMatrix;
uniform vec3 cameraPosition; uniform vec3 cameraPosition;
uniform sampler2D texture; uniform sampler2D tx0;
uniform float materialShininess; uniform sampler2D tx1;
uniform vec3 materialSpecularColor;
uniform bool b_transparent; uniform struct Material {
uniform bool b_specular; float shininess;
uniform bool b_light; vec3 specularColor;
bool isTransparent;
bool hasSpecularmap;
bool hasNormalmap;
bool isGlow;
} material;
uniform bool useLight;
uniform struct Light { uniform struct Light {
vec4 position; vec4 position;
@@ -25,64 +31,96 @@ uniform struct Light {
varying vec2 v_surfaceUV; varying vec2 v_surfaceUV;
varying vec3 v_surfacePosition; varying vec3 v_surfacePosition;
varying vec3 v_surfaceNormal; varying vec3 v_surfaceNormal;
varying vec3 v_polyNorm;
varying vec3 v_polyTan;
varying vec3 v_polyBiTan;
void main() void main()
{ {
if(b_light) if(useLight && !material.isGlow)
{ {
// some values // get the color and undo gamma correction
vec3 normalWorld = normalize(n_matrix * v_surfaceNormal); vec4 surfaceColor = vec4(texture2D(tx0, v_surfaceUV));
vec4 surfaceColor = vec4(texture2D(texture, v_surfaceUV));
surfaceColor.rgb = pow(surfaceColor.rgb, vec3(2.2)); surfaceColor.rgb = pow(surfaceColor.rgb, vec3(2.2));
vec3 surfaceToLight; // attenutation depending on the distance to the light
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); float distanceToLight = length(light.position.xyz - v_surfacePosition);
attenuation = 1.0 / (1.0 + light.attenuationFactor * pow(distanceToLight, 2)); 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); 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; 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; vec3 diffuse = diffuseCoefficient * surfaceColor.rgb * light.intensities;
// specular
/////////////////////////////////////////////////////////////////////////////////////
// specular component
float specularCoefficient = 0.0; float specularCoefficient = 0.0;
if(diffuseCoefficient > 0.0) if(diffuseCoefficient > 0.0)
specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normalWorld))), materialShininess); specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normal))), material.shininess);
if(b_specular)
materialSpecularColor = vec3(surfaceColor.a);
vec3 specular = specularCoefficient * materialSpecularColor * light.intensities;
// linear color before gamma correction) float specularWeight = 1;
if(material.hasSpecularmap)
specularWeight = surfaceColor.a;
vec3 specColor = specularWeight * 1/255 * material.specularColor;
vec3 specular = specularCoefficient * specColor * light.intensities;
/////////////////////////////////////////////////////////////////////////////////////
// linear color before gamma correction
vec3 linearColor = ambient + attenuation * (diffuse + specular); vec3 linearColor = ambient + attenuation * (diffuse + specular);
// final color after gama correction /////////////////////////////////////////////////////////////////////////////////////
// gama correction
vec3 gamma = vec3(1.0/2.2); 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); gl_FragColor = vec4(pow(linearColor, gamma), surfaceColor.a);
} }
// don't use light
else else
{ {
vec4 surfaceColor = vec4(texture2D(texture, v_surfaceUV)); vec4 surfaceColor = vec4(texture2D(tx0, v_surfaceUV));
if(!b_transparent)
surfaceColor.a = 1.0f; if(!material.isTransparent)
surfaceColor.a = 1.0;
gl_FragColor = surfaceColor; 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; precision mediump float;
#endif #endif
uniform mat4 vp_matrix; uniform mat4 viewProjection;
uniform mat4 norm_matrix; uniform mat4 normalizeModel;
uniform mat4 m_matrix; uniform mat4 modelMatrix;
attribute vec4 a_position; attribute vec4 a_position;
attribute vec2 a_texcoord; attribute vec2 a_texcoord;
attribute vec3 a_normal; attribute vec3 a_normal;
attribute vec3 a_polyNorm;
attribute vec3 a_polyTan;
attribute vec3 a_polyBiTan;
varying vec2 v_surfaceUV; varying vec2 v_surfaceUV;
varying vec3 v_surfacePosition; varying vec3 v_surfacePosition;
varying vec3 v_surfaceNormal; varying vec3 v_surfaceNormal;
varying vec3 v_polyNorm;
varying vec3 v_polyTan;
varying vec3 v_polyBiTan;
void main() void main()
{ {
// Calculate vertex position in screen space // 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 // Pass data to fragment shader
// Value will be automatically interpolated to fragments inside polygon faces // Value will be automatically interpolated to fragments inside polygon faces
v_surfaceUV = a_texcoord; 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_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\MshFile.h"
#include "..\Header\OglViewerWidget.h" #include "..\Header\OglViewerWidget.h"
#include "..\Header\MainWindow.h" #include "..\Header\MainWindow.h"
#include <cmath> #include "..\Header\OutputDevice.h"
#include <QRegExp> #include <QRegExp>
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// public constructor/destructor // constructor/destructor
GeometryEngine::GeometryEngine(QObject *parent) GeometryEngine::GeometryEngine(QObject *parent)
: QObject(parent) : QObject(parent)
, m_indexBuf(QOpenGLBuffer::IndexBuffer) , m_indexBuf(QOpenGLBuffer::IndexBuffer)
, m_defaultMaterial(FileInterface::getDefaultMaterial())
{ {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
m_defaultMaterial = FileInterface::getDefaultMaterial();
} }
GeometryEngine::~GeometryEngine() GeometryEngine::~GeometryEngine()
@@ -27,7 +26,7 @@ GeometryEngine::~GeometryEngine()
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// private functions // functions
void GeometryEngine::clearData() void GeometryEngine::clearData()
{ {
@@ -52,9 +51,139 @@ void GeometryEngine::clearData()
m_drawList.clear(); m_drawList.clear();
} }
void GeometryEngine::setupPipeline(QOpenGLShaderProgram *program)
{
// Offset for position
quintptr offset = 0;
///////////////////////////////////////////////////////////////////////// // Tell OpenGL programmable pipeline how to locate vertex position data
// public slots 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) void GeometryEngine::loadFile(QString filePath)
{ {
@@ -65,7 +194,7 @@ void GeometryEngine::loadFile(QString filePath)
//reset view //reset view
emit requestResetView(); emit requestResetView();
emit sendMessage("loading file..", 0); OutputDevice::getInstance()->print("loading file..", 0);
try try
{ {
@@ -74,7 +203,7 @@ void GeometryEngine::loadFile(QString filePath)
QVector<GLuint> indexData; QVector<GLuint> indexData;
// open file and get the information // open file and get the information
MshFile file(filePath, this); MshFile file(filePath);
models = file.getModels(); models = file.getModels();
m_materials = file.getMaterials(); m_materials = file.getMaterials();
@@ -104,7 +233,7 @@ void GeometryEngine::loadFile(QString filePath)
vertexData += segmentIterator->vertices; vertexData += segmentIterator->vertices;
indexData += segmentIterator->indices; 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); m_drawList.push_back(new_info);
else else
m_drawList.push_front(new_info); m_drawList.push_front(new_info);
@@ -124,104 +253,13 @@ void GeometryEngine::loadFile(QString filePath)
m_indexBuf.allocate(indexData.data(), indexData.size() * sizeof(GLuint)); m_indexBuf.allocate(indexData.data(), indexData.size() * sizeof(GLuint));
emit requestUpdate(); emit requestUpdate();
emit sendMessage("done..", 0); OutputDevice::getInstance()->print("done..", 0);
emit sendFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3); OutputDevice::getInstance()->setFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3);
} }
catch (std::invalid_argument e) catch (std::invalid_argument e)
{ {
clearData(); clearData();
emit sendMessage(QString(e.what()), 2); OutputDevice::getInstance()->print(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);
} }
} }

View File

@@ -1,48 +1,66 @@
#include "..\Header\MainWindow.h" #include "..\Header\MainWindow.h"
#include "..\Header\OglViewerWidget.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\FileInterface.h"
#include "..\Header\OutputDevice.h"
#include "..\Header\SettingsManager.h"
#include <QSurfaceFormat>
#include <QSignalMapper>
#include <QToolButton>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QPalette>
#include <QResizeEvent>
#include <QDirIterator>
#include <QFileInfo>
#define WINDOW_NAME "Mesh Viewer" #define WINDOW_NAME "Mesh Viewer"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::MainWindowClass) , ui(new Ui::MainWindowClass)
, m_curSeverity(0)
, m_output(new QLabel(this)) , m_output(new QLabel(this))
, m_curSeverity(0)
, m_infoWindow(new FileInfoWindow(this)) , m_infoWindow(new FileInfoWindow(this))
{ {
// setup window
ui->setupUi(this); ui->setupUi(this);
setWindowTitle(WINDOW_NAME); setWindowTitle(WINDOW_NAME);
setWindowIcon(QIcon(":/images/icon.ico")); 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; QSurfaceFormat format;
format.setDepthBufferSize(24); format.setDepthBufferSize(24);
format.setMajorVersion(2);
format.setMinorVersion(0);
format.setProfile(QSurfaceFormat::NoProfile);
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
// set default text to file info
m_fileInfo = "Filename: -\nMaterials: -\nVertices: -\nTriangle: -<detail>No file is open";
ui->dirDropDownList->addItem("BF1_ModTools", "C:/BF1_ModTools/Assets/Shipped Worlds/");
ui->dirDropDownList->addItem("BF2_ModTools", "C:/BF2_ModTools/assets/Sides/");
// add widgets to the window
setupWidgets(); setupWidgets();
printMessage("MeshViewer by Anakin", 0); // load stylesheet
m_fileInfo += "Filename: -\nMaterials: -\nVertices: -\nTriangle: -<detail>No file is open";
QFile styleSheet(":/files/StyleSheet.txt"); QFile styleSheet(":/files/StyleSheet.txt");
styleSheet.open(QIODevice::ReadOnly); styleSheet.open(QIODevice::ReadOnly);
this->setStyleSheet(styleSheet.readAll()); this->setStyleSheet(styleSheet.readAll());
// setup dropdown
setupAssetLibrary();
connect(SettingsManager::getInstance(), &SettingsManager::dirsChanged, this, &MainWindow::setupAssetLibrary);
printMessage("MeshViewer by Anakin", 0);
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@@ -52,68 +70,57 @@ MainWindow::~MainWindow()
delete m_infoWindow; delete m_infoWindow;
} }
void MainWindow::openFile() /////////////////////////////////////////////////////////////////////////
{ // functions
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Mesh (*.msh)");
if(!fileName.isEmpty())
emit loadFile(fileName);
}
void MainWindow::setupWidgets() void MainWindow::setupWidgets()
{ {
// Ogl Viewer
OglViewerWidget* viewer = new OglViewerWidget(this); OglViewerWidget* viewer = new OglViewerWidget(this);
setCentralWidget(viewer); setCentralWidget(viewer);
connect(viewer, &OglViewerWidget::sendMessage, this, &MainWindow::printMessage); connect(this, &MainWindow::loadFile, viewer, &OglViewerWidget::loadFile);
QToolButton *openFile = new QToolButton(this); // open file
openFile->setObjectName("openFile"); QToolButton *openFileDialog = new QToolButton(this);
openFile->setToolTip("open file"); openFileDialog->setObjectName("openFile");
connect(openFile, &QToolButton::pressed, this, &MainWindow::openFile); openFileDialog->setToolTip("open file");
ui->mainToolBar->addWidget(openFile); connect(openFileDialog, &QToolButton::pressed, this, &MainWindow::openFileDialog);
ui->mainToolBar->addWidget(openFileDialog);
// screenshot
QToolButton *screenshot = new QToolButton(this); QToolButton *screenshot = new QToolButton(this);
screenshot->setObjectName("screenshot"); screenshot->setObjectName("screenshot");
screenshot->setToolTip("take screenshot"); screenshot->setToolTip("take screenshot");
connect(screenshot, &QToolButton::pressed, this, &MainWindow::takeScreenShot); connect(screenshot, &QToolButton::pressed, this, &MainWindow::takeScreenShot);
ui->mainToolBar->addWidget(screenshot); ui->mainToolBar->addWidget(screenshot);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator(); 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); // Orbital Camera
x->setObjectName("x"); QToolButton *orbitCamera = new QToolButton(this);
x->setToolTip("x-direction"); orbitCamera->setObjectName("orbitalCamera");
x->setCheckable(true); orbitCamera->setToolTip("orbital camera");
x->setChecked(true); connect(orbitCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useOrbitCamera);
ui->mainToolBar->addWidget(x); ui->mainToolBar->addWidget(orbitCamera);
QToolButton *y = new QToolButton(this); // Move Camera
y->setObjectName("y"); QToolButton *walkCamera = new QToolButton(this);
y->setToolTip("y-direction"); walkCamera->setObjectName("walkCamera");
y->setCheckable(true); walkCamera->setToolTip("walk camera");
y->setChecked(true); connect(walkCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useMoveCamera);
ui->mainToolBar->addWidget(y); ui->mainToolBar->addWidget(walkCamera);
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)));
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator(); ui->mainToolBar->addSeparator();
// wireframe
QToolButton *wireframe = new QToolButton(this); QToolButton *wireframe = new QToolButton(this);
wireframe->setObjectName("wireframe"); wireframe->setObjectName("wireframe");
wireframe->setToolTip("wireframe"); wireframe->setToolTip("wireframe");
@@ -122,6 +129,7 @@ void MainWindow::setupWidgets()
connect(wireframe, &QToolButton::pressed, viewer, &OglViewerWidget::toggleWireframe); connect(wireframe, &QToolButton::pressed, viewer, &OglViewerWidget::toggleWireframe);
ui->mainToolBar->addWidget(wireframe); ui->mainToolBar->addWidget(wireframe);
// light
QToolButton *light = new QToolButton(this); QToolButton *light = new QToolButton(this);
light->setObjectName("light"); light->setObjectName("light");
light->setToolTip("toggle light"); light->setToolTip("toggle light");
@@ -130,48 +138,71 @@ void MainWindow::setupWidgets()
connect(light, &QToolButton::pressed, viewer, &OglViewerWidget::toggleLight); connect(light, &QToolButton::pressed, viewer, &OglViewerWidget::toggleLight);
ui->mainToolBar->addWidget(light); ui->mainToolBar->addWidget(light);
// settings
QToolButton *settings = new QToolButton(this); QToolButton *settings = new QToolButton(this);
settings->setObjectName("settings"); settings->setObjectName("settings");
settings->setToolTip("settings"); settings->setToolTip("settings");
connect(settings, &QToolButton::pressed, viewer, &OglViewerWidget::showSettings); connect(settings, &QToolButton::pressed, viewer, &OglViewerWidget::showSettings);
ui->mainToolBar->addWidget(settings); ui->mainToolBar->addWidget(settings);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator(); ui->mainToolBar->addSeparator();
// fileinfo
QToolButton *fileInfo = new QToolButton(this); QToolButton *fileInfo = new QToolButton(this);
fileInfo->setObjectName("fileInfo"); fileInfo->setObjectName("fileInfo");
fileInfo->setToolTip("file info"); fileInfo->setToolTip("file info");
connect(fileInfo, &QToolButton::pressed, this, &MainWindow::aboutFile); connect(fileInfo, &QToolButton::pressed, m_infoWindow, &FileInfoWindow::show);
ui->mainToolBar->addWidget(fileInfo); ui->mainToolBar->addWidget(fileInfo);
// help
QToolButton *help = new QToolButton(this); QToolButton *help = new QToolButton(this);
help->setObjectName("help"); help->setObjectName("help");
help->setToolTip("help"); help->setToolTip("help");
connect(help, &QToolButton::pressed, this, &MainWindow::aboutTool); connect(help, &QToolButton::pressed, this, &MainWindow::aboutTool);
ui->mainToolBar->addWidget(help); ui->mainToolBar->addWidget(help);
// output on screen
m_output->setObjectName("output"); m_output->setObjectName("output");
m_output->setStyleSheet("QLabel#output{color : white; min-width: 400px; min-height: 50px;}");
m_output->setAlignment(Qt::AlignTop); 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(); m_output->raise();
} }
void MainWindow::aboutFile() void MainWindow::updateAssetTree(QString path)
{ {
/*QMessageBox* dialog = new QMessageBox(QMessageBox::NoIcon,
WINDOW_NAME,
QString(m_fileInfo.left(m_fileInfo.indexOf("<detail>"))),
QMessageBox::StandardButton::Close,
this,
Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
dialog->setStyleSheet("QLabel{min-width: 200px;}"); ui->fileTreeWidget->clear();
dialog->setDetailedText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("<detail>") - 8))); QDirIterator itterator(path, QStringList() << "*.msh" << "*.MSH" << "*.mesh" << "*.MESH",
dialog->exec(); QDir::Files, QDirIterator::Subdirectories);
delete dialog;*/
m_infoWindow->show(); while (itterator.hasNext()) {
QTreeWidgetItem* sub = new QTreeWidgetItem(ui->fileTreeWidget);
sub->setData(0, Qt::DisplayRole, itterator.fileName());
sub->setData(1, Qt::DisplayRole, itterator.fileInfo().absoluteFilePath());
itterator.next();
}
}
void MainWindow::openFileDialog()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Mesh (*.msh)");
openFile(fileName);
}
void MainWindow::openFile(QString fileName)
{
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() void MainWindow::aboutTool()
@@ -193,22 +224,77 @@ void MainWindow::aboutTool()
delete dialog; 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) void MainWindow::resizeEvent(QResizeEvent * e)
{ {
m_output->move(40, e->size().height() - 80); m_output->move(40, e->size().height() - 80);
} }
/////////////////////////////////////////////////////////////////////////
// slots
void MainWindow::setupAssetLibrary()
{
// get all directories and put them in the dropdown.
while (ui->dirDropDownList->count() != 0)
ui->dirDropDownList->removeItem(0);
QStringList tmp_list = SettingsManager::getInstance()->getListOfDirs();
for (QString &it : tmp_list)
ui->dirDropDownList->addItem(it, it);
// choose the current path and display it.
if (ui->dirDropDownList->currentData().isValid())
updateAssetTree(ui->dirDropDownList->currentData().toString());
}
void MainWindow::on_fileTreeWidget_doubleClicked()
{
QString clickedFile = ui->fileTreeWidget->currentItem()->text(1);
openFile(clickedFile);
}
void MainWindow::on_dirDropDownList_currentTextChanged(const QString &arg1)
{
QString selectedDir;
selectedDir = ui->dirDropDownList->itemData(ui->dirDropDownList->currentIndex()).toString();
printMessage(arg1 + " : " + selectedDir, 0);
updateAssetTree(selectedDir);
}
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) void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle)
{ {
// save basic file information
m_fileInfo = QByteArray("Filename: "); m_fileInfo = QByteArray("Filename: ");
m_fileInfo += name; m_fileInfo += name;
m_fileInfo += "\nMaterials: "; m_fileInfo += "\nMaterials: ";
@@ -219,6 +305,7 @@ void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int ver
m_fileInfo += QByteArray::number(triangle); m_fileInfo += QByteArray::number(triangle);
m_fileInfo += "<detail>"; m_fileInfo += "<detail>";
// add detailed information
for (auto& it : *materials) for (auto& it : *materials)
{ {
m_fileInfo += it.name; m_fileInfo += it.name;
@@ -307,39 +394,11 @@ void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int ver
m_fileInfo += "-----------------------------------------------------------------\n"; m_fileInfo += "-----------------------------------------------------------------\n";
} }
// print basic information on screen
m_output->setText(m_fileInfo.left(m_fileInfo.indexOf("<detail>"))); 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->setBasicText(QString(m_fileInfo.left(m_fileInfo.indexOf("<detail>"))));
m_infoWindow->setDetailText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("<detail>") - 8))); 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\MshFile.h"
#include "..\Header\tga.h" #include "..\Header\tga.h"
#include <QColor> #include "..\Header\OutputDevice.h"
#include <QVector3D>
// helper function to save data from file to any variable type // helper function to save data from file to any variable type
#define F2V(variableName) reinterpret_cast<char*>(&variableName) #define F2V(variableName) reinterpret_cast<char*>(&variableName)
@@ -9,8 +11,8 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// public constructor/destructor // public constructor/destructor
MshFile::MshFile(QString path, QObject * parent) MshFile::MshFile(QString path)
: FileInterface(path, parent) : FileInterface(path)
{ {
import(); import();
} }
@@ -26,22 +28,22 @@ MshFile::~MshFile()
void MshFile::import() void MshFile::import()
{ {
// go to file size information // go to file size information
m_file.seekg(4); m_file.seek(4);
std::uint32_t tmp_fileSize; quint32 tmp_fileSize;
std::list<ChunkHeader*> tmp_mainChunks; QList<ChunkHeader*> tmp_mainChunks;
// get all chunks under HEDR // get all chunks under HEDR
m_file.read(F2V(tmp_fileSize), sizeof(tmp_fileSize)); 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) // evaulate HEDR subchunks (= find MSH2)
for (ChunkHeader* it : tmp_mainChunks) for (ChunkHeader* it : tmp_mainChunks)
{ {
if (!strcmp("MSH2", it->name)) if ("MSH2" == it->name)
{ {
// get all subchunks // get all subchunks
std::list<ChunkHeader*> tmp_msh2Chunks; QList<ChunkHeader*> tmp_msh2Chunks;
loadChunks(tmp_msh2Chunks, it->position, it->size); loadChunks(tmp_msh2Chunks, it->position, it->size);
// evaluate MSH2 subchunks // 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 // jump to first chunk
m_file.seekg(start); m_file.seek(start);
do 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(); ChunkHeader* tmp_header = new ChunkHeader();
// get information // 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)); 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 // store information
destination.push_back(tmp_header); destination.push_back(tmp_header);
// jump to next 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 } while (m_file.pos() - start != length);
if (!m_file.good())
{
emit sendMessage("WARNING: corrupted file. Trying to continue..", 1);
m_file.clear();
break;
}
} while (m_file.tellg() - start != length);
} }
void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList) void MshFile::analyseMsh2Chunks(QList<ChunkHeader*>& chunkList)
{ {
for (auto& it : chunkList) for (auto& it : chunkList)
{ {
// scene information // scene information
if (!strcmp("SINF", it->name)) if ("SINF" == it->name)
{ {
// get SINF subchunks // get SINF subchunks
std::list<ChunkHeader*> tmp_sinfChunks; QList<ChunkHeader*> tmp_sinfChunks;
loadChunks(tmp_sinfChunks, it->position, it->size); loadChunks(tmp_sinfChunks, it->position, it->size);
// evaluate SINF subchunks // evaluate SINF subchunks
for (auto& it : tmp_sinfChunks) 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 // read in the quaternion
float tmp_quat[4]; float tmp_quat[4];
@@ -141,24 +146,25 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
} }
// material list // 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 // "useless" information how many MATD follow, jump over it
m_file.seekg(it->position); m_file.seek(it->position);
m_file.seekg(sizeof(std::uint32_t), std::ios_base::cur); m_file.seek(sizeof(quint32) + m_file.pos());
// get all MATL subchunk // get all MATL subchunk
std::list<ChunkHeader*> tmp_matlChunks; QList<ChunkHeader*> tmp_matlChunks;
loadChunks(tmp_matlChunks, m_file.tellg(), it->size - 4); loadChunks(tmp_matlChunks, m_file.pos(), it->size - 4);
// evaluate MATL subchunks // evaluate MATL subchunks
for (auto& it : tmp_matlChunks) for (auto& it : tmp_matlChunks)
{ {
// This shouldn't be anything else than MATD // This shouldn't be anything else than MATD
if (!strcmp("MATD", it->name)) if ("MATD" == it->name)
{ {
// get all subchunks from MATD // get all subchunks from MATD
std::list<ChunkHeader*> tmp_matdChunks; QList<ChunkHeader*> tmp_matdChunks;
loadChunks(tmp_matdChunks, it->position, it->size); loadChunks(tmp_matdChunks, it->position, it->size);
m_materials->push_back(Material()); m_materials->push_back(Material());
@@ -186,14 +192,15 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
} }
// model // model
else if (!strcmp("MODL", it->name)) else if ("MODL" == it->name)
{ {
OutputDevice::getInstance()->print("loading model..", 0);
Model* new_model = new Model; Model* new_model = new Model;
m_currentType = ModelTyp::null; m_currentType = ModelTyp::null;
m_currentRenderFlag = -1; m_currentRenderFlag = -1;
// get all MODL subchunks // get all MODL subchunks
std::list<ChunkHeader*> tmp_chunks; QList<ChunkHeader*> tmp_chunks;
loadChunks(tmp_chunks, it->position, it->size); loadChunks(tmp_chunks, it->position, it->size);
// evaluate MODL subchunks // 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) for (auto& it : chunkList)
{ {
// name // 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]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -229,9 +236,9 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
} }
// data // data
else if(!strcmp("DATA", it->name)) else if("DATA" == it->name)
{ {
m_file.seekg(it->position); m_file.seek(it->position);
// diffuse // diffuse
for (unsigned int i = 0; i < 4; i++) for (unsigned int i = 0; i < 4; i++)
@@ -250,18 +257,18 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
} }
// attributes // attributes
else if (!strcmp("ATRB", it->name)) else if ("ATRB" == it->name)
{ {
// get pointer to current material // get pointer to current material
Material* curMat = &m_materials->back(); Material* curMat = &m_materials->back();
// read the attributes // read the attributes
m_file.seekg(it->position); m_file.seek(it->position);
std::uint8_t flag; quint8 flag;
m_file.read(F2V(flag), sizeof(flag)); m_file.read(F2V(flag), sizeof(flag));
m_file.read(F2V(curMat->rendertype), sizeof(std::uint8_t)); m_file.read(F2V(curMat->rendertype), sizeof(quint8));
m_file.read(F2V(curMat->dataValues[0]), sizeof(std::uint8_t)); m_file.read(F2V(curMat->dataValues[0]), sizeof(quint8));
m_file.read(F2V(curMat->dataValues[1]), sizeof(std::uint8_t)); m_file.read(F2V(curMat->dataValues[1]), sizeof(quint8));
// flags // flags
// 0: emissive // 0: emissive
@@ -274,17 +281,16 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
// 7: specular // 7: specular
for (unsigned int i = 0; i < 8; i++) 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; curMat->transparent = curMat->flags[2] || curMat->flags[3] || curMat->flags[4] || curMat->flags[6] || curMat->rendertype == 4;
} }
// texture 0 // texture 0
else if (!strcmp("TX0D", it->name)) else if ("TX0D" == it->name)
{ {
// get the texture name // get the texture name
m_file.seekg(it->position); m_file.seek(it->position);
char* buffer = new char[it->size + 1]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -297,10 +303,10 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
} }
// texture 1 // texture 1
else if (!strcmp("TX1D", it->name)) else if ("TX1D" == it->name)
{ {
// get the texture name // get the texture name
m_file.seekg(it->position); m_file.seek(it->position);
char* buffer = new char[it->size + 1]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -309,14 +315,13 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
if (!m_materials->back().tx1d.isEmpty()) if (!m_materials->back().tx1d.isEmpty())
loadTexture(m_materials->back().texture1, m_filepath, m_materials->back().tx1d); loadTexture(m_materials->back().texture1, m_filepath, m_materials->back().tx1d);
} }
// texture 2 // texture 2
else if (!strcmp("TX2D", it->name)) else if ("TX2D" == it->name)
{ {
// get the texture name // get the texture name
m_file.seekg(it->position); m_file.seek(it->position);
char* buffer = new char[it->size + 1]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -325,10 +330,10 @@ void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
} }
// texture 3 // texture 3
else if (!strcmp("TX3D", it->name)) else if ("TX3D" == it->name)
{ {
// get the texture name // get the texture name
m_file.seekg(it->position); m_file.seek(it->position);
char* buffer = new char[it->size + 1]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); 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) for (auto& it : chunkList)
{ {
// model type // model type
if (!strcmp("MTYP", it->name)) if ("MTYP" == it->name)
{ {
m_file.seekg(it->position); m_file.seek(it->position);
std::uint32_t tmp_type; quint32 tmp_type;
m_file.read(F2V(tmp_type), sizeof(tmp_type)); m_file.read(F2V(tmp_type), sizeof(tmp_type));
m_currentType = (ModelTyp)tmp_type; m_currentType = (ModelTyp)tmp_type;
} }
// parent name // 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]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -363,9 +368,9 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
} }
// model name // 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]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -374,20 +379,20 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
} }
// render flags // 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)); m_file.read(F2V(m_currentRenderFlag), sizeof(m_currentRenderFlag));
} }
// translation // translation
else if (!strcmp("TRAN", it->name)) else if ("TRAN" == it->name)
{ {
float tmp_scale[3]; float tmp_scale[3];
float tmp_rotation[4]; float tmp_rotation[4];
float tmp_trans[3]; float tmp_trans[3];
m_file.seekg(it->position); m_file.seek(it->position);
// read in the data // read in the data
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
@@ -410,14 +415,14 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
} }
// geometry data // geometry data
else if (!strcmp("GEOM", it->name)) else if ("GEOM" == it->name)
{ {
// don't get null, bone, shadowMesh and hidden mesh indices // don't get null, bone, shadowMesh and hidden mesh indices
if (m_currentType == null || m_currentType == bone || m_currentType == shadowMesh || m_currentRenderFlag == 1) if (m_currentType == null || m_currentType == bone || m_currentType == shadowMesh || m_currentRenderFlag == 1)
continue; continue;
// get all GEOM subchunks // get all GEOM subchunks
std::list<ChunkHeader*> tmp_geomChunks; QList<ChunkHeader*> tmp_geomChunks;
loadChunks(tmp_geomChunks, it->position, it->size); loadChunks(tmp_geomChunks, it->position, it->size);
// evaluate GEOM subchunks // 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) for (auto& it : chunkList)
{ {
// segment // segment
if (!strcmp("SEGM", it->name)) if ("SEGM" == it->name)
{ {
// get all SEGM subchunks // get all SEGM subchunks
std::list<ChunkHeader*> tmp_segmChunks; QList<ChunkHeader*> tmp_segmChunks;
loadChunks(tmp_segmChunks, it->position, it->size); loadChunks(tmp_segmChunks, it->position, it->size);
// evaluate SEGM subchunks // evaluate SEGM subchunks
@@ -458,10 +463,10 @@ void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>
} }
// cloth // cloth
else if (!strcmp("CLTH", it->name)) else if ("CLTH" == it->name)
{ {
// get all CLTH subchunks // get all CLTH subchunks
std::list<ChunkHeader*> tmp_clthChunks; QList<ChunkHeader*> tmp_clthChunks;
loadChunks(tmp_clthChunks, it->position, it->size); loadChunks(tmp_clthChunks, it->position, it->size);
// evaluate CLTH subchunks // 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; Segment* new_segment = new Segment;
for (auto& it : chunkList) for (auto& it : chunkList)
{ {
// material index // 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)); m_file.read(F2V(new_segment->textureIndex), sizeof(new_segment->textureIndex));
} }
// position list (vertex) // position list (vertex)
else if (!strcmp("POSL", it->name)) else if ("POSL" == it->name)
{ {
readVertex(new_segment, it->position); readVertex(new_segment, it->position);
} }
// normals // normals
else if (!strcmp("NRML", it->name)) else if ("NRML" == it->name)
{ {
std::uint32_t tmp_size; quint32 tmp_size;
m_file.seekg(it->position); m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size)); 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 i = new_segment->vertices.size(); i != tmp_size; i--)
for (unsigned int j = 0; j < 3; j++) for (unsigned int j = 0; j < 3; j++)
new_segment->vertices[i - 1].vertexNormal[j] = 0; 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(); tmp_size = new_segment->vertices.size();
} }
@@ -525,18 +530,18 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
} }
// uv // uv
else if (!strcmp("UV0L", it->name)) else if ("UV0L" == it->name)
{ {
readUV(new_segment, it->position); readUV(new_segment, it->position);
} }
// polygons (indices into vertex/uv list) // 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; // jump to the data section and read the size;
std::uint32_t tmp_size; quint32 tmp_size;
m_file.seekg(it->position); m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size)); m_file.read(F2V(tmp_size), sizeof(tmp_size));
int highBitCount(0); int highBitCount(0);
@@ -545,7 +550,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
for (unsigned int i = 0; i < tmp_size; i++) for (unsigned int i = 0; i < tmp_size; i++)
{ {
// ReadData // ReadData
std::uint16_t tmp_value; quint16 tmp_value;
m_file.read(F2V(tmp_value), sizeof(tmp_value)); m_file.read(F2V(tmp_value), sizeof(tmp_value));
// Check if highbit is set // Check if highbit is set
@@ -553,7 +558,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
{ {
highBitCount++; highBitCount++;
// remove the high bit, to get the actually value // 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 // save data
@@ -567,18 +572,106 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
if (tmp_buffer.size() == 5) if (tmp_buffer.size() == 5)
{ {
for (size_t i = 0; i < 3; i++) // calculate poylgon normal, tangent and bitangent
new_segment->indices.push_back(tmp_buffer.takeFirst()); 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) else if (tmp_buffer.size() > 5)
{ {
unsigned int tmp_multiPolySize = tmp_buffer.size() - 2; 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 every triangle of the multi polygon..
for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++) for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
{
// ..calculate the edge indices // ..calculate the edge indices
for (int triEdge = 0; triEdge < 3; triEdge++) 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); 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) // save the last polygon (no 2 high bit followed)
if (tmp_buffer.size() == 3) if (tmp_buffer.size() == 3)
{ {
for (size_t i = 0; i < 3; i++) // calculate poylgon normal, tangent and bitangent
new_segment->indices.push_back(tmp_buffer.takeFirst()); 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) else if (tmp_buffer.size() > 3)
{ {
unsigned int tmp_multiPolySize = tmp_buffer.size(); 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 every triangle of the multi polygon..
for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++) for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
{
// ..calculate the edge indices // ..calculate the edge indices
for (int triEdge = 0; triEdge < 3; triEdge++) 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); 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; Segment* new_segment = new Segment;
for (auto& it : chunkList) for (auto& it : chunkList)
{ {
// texture name // texture name
if (!strcmp("CTEX", it->name)) if ("CTEX" == it->name)
{ {
// read the texture name // read the texture name
m_file.seekg(it->position); m_file.seek(it->position);
char* buffer = new char[it->size + 1]; char* buffer = new char[it->size + 1];
*buffer = { 0 }; *buffer = { 0 };
m_file.read(buffer, it->size); m_file.read(buffer, it->size);
@@ -638,32 +820,46 @@ void MshFile::analyseClthChunks(Model * dataDestination, std::list<ChunkHeader*>
} }
// position list (vertex) // position list (vertex)
else if (!strcmp("CPOS", it->name)) else if ("CPOS" == it->name)
{ {
readVertex(new_segment, it->position); readVertex(new_segment, it->position);
} }
// uv // uv
else if (!strcmp("CUV0", it->name)) else if ("CUV0" == it->name)
{ {
readUV(new_segment, it->position); readUV(new_segment, it->position);
} }
// triangles (indices into vertex/uv list) // 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; // jump to the data section and read the size;
std::uint32_t tmp_size; quint32 tmp_size;
m_file.seekg(it->position); m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size)); m_file.read(F2V(tmp_size), sizeof(tmp_size));
// for every triangle.. // 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; quint32 tmp_value[3];
m_file.read(F2V(tmp_value), sizeof(std::uint32_t)); 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); 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; quint32 tmp_size;
m_file.seekg(position); m_file.seek(position);
m_file.read(F2V(tmp_size), sizeof(tmp_size)); m_file.read(F2V(tmp_size), sizeof(tmp_size));
for (unsigned int i = 0; i < tmp_size; i++) 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; quint32 tmp_size;
m_file.seekg(position); m_file.seek(position);
m_file.read(F2V(tmp_size), sizeof(tmp_size)); 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 i = dataDestination->vertices.size(); i != tmp_size; i--)
for (unsigned int j = 0; j < 2; j++) for (unsigned int j = 0; j < 2; j++)
dataDestination->vertices[i - 1].texCoord[j] = 0; 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(); 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) void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
{ {
bool loadSuccess(false); bool loadSuccess(false);
QImage img = loadTga(filepath + "/" + filename, loadSuccess); QImage img = loadTga(filepath + "/" + filename, loadSuccess);
if (!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 = 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)); img.fill(QColor(m_materials->back().diffuseColor[0] * 255, m_materials->back().diffuseColor[1] * 255, m_materials->back().diffuseColor[2] * 255));
filename += " *"; filename += " *";
@@ -745,13 +942,13 @@ void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QStri
destination = new_texture; destination = new_texture;
} }
QMatrix4x4 MshFile::getParentMatrix(std::string parent) const QMatrix4x4 MshFile::getParentMatrix(QString parent) const
{ {
QMatrix4x4 matrix; QMatrix4x4 matrix;
for (auto& it : *m_models) for (auto& it : *m_models)
{ {
if (!strcmp(parent.c_str(), it->name.c_str())) if (parent == it->name)
{ {
matrix = getParentMatrix(it->parent) * it->m4x4Translation; matrix = getParentMatrix(it->parent) * it->m4x4Translation;
break; break;
@@ -761,13 +958,13 @@ QMatrix4x4 MshFile::getParentMatrix(std::string parent) const
return matrix; return matrix;
} }
QQuaternion MshFile::getParentRotation(std::string parent) const QQuaternion MshFile::getParentRotation(QString parent) const
{ {
QQuaternion rotation; QQuaternion rotation;
for (auto& it : *m_models) for (auto& it : *m_models)
{ {
if (!strcmp(parent.c_str(), it->name.c_str())) if (parent == it->name)
{ {
rotation = getParentRotation(it->parent) * it->quadRotation; rotation = getParentRotation(it->parent) * it->quadRotation;
break; break;

View File

@@ -1,31 +1,41 @@
#include "..\Header\OglViewerWidget.h" #include "..\Header\OglViewerWidget.h"
#include "..\Header\MainWindow.h" #include "..\Header\MainWindow.h"
#include "..\Header\FreeCamera.h"
#include "..\Header\OrbitCamera.h"
#include "..\Header\MoveCamera.h"
#include "..\Header\SettingsManager.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QDropEvent> #include <QDropEvent>
#include <QMimeData> #include <QMimeData>
#include <math.h>
#include <iostream> #include "..\Header\Profiler.h"
#define DEFAULT_Z_DISTANCE -4.0 #define DEFAULT_Z_DISTANCE -4.0
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// public constructor/destructor // constructor/destructor
OglViewerWidget::OglViewerWidget(QWidget *parent) OglViewerWidget::OglViewerWidget(QWidget *parent)
: QOpenGLWidget(parent) : QOpenGLWidget(parent)
, m_dataEngine(0) , m_dataEngine(Q_NULLPTR)
, m_settings(new SettingsWindow(this)) , m_camera(new FreeCamera)
{ {
setFocus(); setFocus();
m_translation.setZ(DEFAULT_Z_DISTANCE);
setAcceptDrops(true); setAcceptDrops(true);
// settings window
setDefaultValues();
m_settings = new SettingsWindow(this);
connect(m_settings, &SettingsWindow::updateBGColorOff, this, &OglViewerWidget::setBGColorOff); connect(m_settings, &SettingsWindow::updateBGColorOff, this, &OglViewerWidget::setBGColorOff);
connect(m_settings, &SettingsWindow::updateBGColorOn, this, &OglViewerWidget::setBGColorOn); connect(m_settings, &SettingsWindow::updateBGColorOn, this, &OglViewerWidget::setBGColorOn);
connect(m_settings, &SettingsWindow::updateLightColor, this, &OglViewerWidget::setLightColor); connect(m_settings, &SettingsWindow::updateLightColor, this, &OglViewerWidget::setLightColor);
connect(m_settings, &SettingsWindow::updateAttFac, this, &OglViewerWidget::setAttFac); connect(m_settings, &SettingsWindow::updateAttFac, this, &OglViewerWidget::setAttFac);
connect(m_settings, &SettingsWindow::updateAmbCoef, this, &OglViewerWidget::setAmbCoef); 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() OglViewerWidget::~OglViewerWidget()
@@ -36,12 +46,155 @@ OglViewerWidget::~OglViewerWidget()
delete m_dataEngine; delete m_dataEngine;
doneCurrent(); doneCurrent();
delete m_camera;
delete m_settings; 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) void OglViewerWidget::mousePressEvent(QMouseEvent *e)
{ {
@@ -68,95 +221,109 @@ void OglViewerWidget::mouseMoveEvent(QMouseEvent *e)
if (m_mouse.left) if (m_mouse.left)
{ {
// get the difference between last press and now // 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 // update the new position
m_mouse.position = QVector2D(e->localPos()); 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 // request an update
if (m_light.headlight)
updateLightPosition();
update(); update();
} }
else if (m_mouse.right) else if (m_mouse.right)
{ {
// get the difference between last press and now // 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 // update the new position
m_mouse.position = QVector2D(e->localPos()); 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 // request an update
if (m_light.headlight)
updateLightPosition();
update(); update();
} }
} }
void OglViewerWidget::wheelEvent(QWheelEvent *e) 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(); 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) void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e)
{ {
if (e->mimeData()->hasUrls()) if (e->mimeData()->hasUrls())
@@ -168,200 +335,57 @@ void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e)
void OglViewerWidget::dropEvent(QDropEvent * e) void OglViewerWidget::dropEvent(QDropEvent * e)
{ {
emit loadFile(e->mimeData()->urls().first().toLocalFile()); m_dataEngine->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();
} }
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// public slots // public slots
void OglViewerWidget::changeDirection(int direction) void OglViewerWidget::loadFile(QString name)
{ {
switch (direction) m_dataEngine->loadFile(name);
{ }
case 1:
m_rotDirections.x = !m_rotDirections.x; void OglViewerWidget::useFreeCamera()
break; {
case 2: delete m_camera;
m_rotDirections.y = !m_rotDirections.y; m_camera = new FreeCamera;
break;
case 3: if (m_lightOn)
m_rotDirections.z = !m_rotDirections.z; updateLightPosition();
break; 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() void OglViewerWidget::toggleWireframe()
{ {
m_wireframe = 1 - m_wireframe; m_wireframe = !m_wireframe;
update(); update();
} }
void OglViewerWidget::toggleLight() void OglViewerWidget::toggleLight()
{ {
m_lightOn = 1 - m_lightOn; m_lightOn = !m_lightOn;
if (m_lightOn) if (m_lightOn)
{ {
@@ -372,6 +396,9 @@ void OglViewerWidget::toggleLight()
{ {
m_backgroundColorOff[3] = 1.0; m_backgroundColorOff[3] = 1.0;
} }
emit lightChanged(m_lightOn);
update(); update();
} }
@@ -419,3 +446,20 @@ void OglViewerWidget::setAmbCoef(double value)
if (m_lightOn) if (m_lightOn)
update(); 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,243 @@
#include "..\Header\SettingsManager.h"
#include "qdebug.h"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
SettingsManager::SettingsManager(QObject *parent)
: QObject(parent)
{
m_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 (m_file.open(QIODevice::ReadOnly))
{
QByteArray stream = m_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();
}
else if (it.startsWith("<qkList>"))
{
m_listOfDirs = QString(it.right(it.size() - it.indexOf('>') - 1)).split(";");
}
}
m_file.close();
}
}
void SettingsManager::writeToFile()
{
m_file.open(QIODevice::WriteOnly);
m_file.write(QString("<bgOn>%1;%2;%3\n").arg(m_bgColorOn.x()).arg(m_bgColorOn.y()).arg(m_bgColorOn.z()).toUtf8());
m_file.write(QString("<bgOff>%1;%2;%3\n").arg(m_bgColorOff.x()).arg(m_bgColorOff.y()).arg(m_bgColorOff.z()).toUtf8());
m_file.write(QString("<liCo>%1;%2;%3\n").arg(m_lightColor.x()).arg(m_lightColor.y()).arg(m_lightColor.z()).toUtf8());
m_file.write(QString("<bfCul>%1\n").arg(m_bfCulling).toUtf8());
m_file.write(QString("<liOn>%1\n").arg(m_light).toUtf8());
m_file.write(QString("<heLi>%1\n").arg(m_headlight).toUtf8());
m_file.write(QString("<auCo>%1\n").arg(m_autoColor).toUtf8());
m_file.write(QString("<liTy>%1\n").arg(m_lightType).toUtf8());
m_file.write(QString("<atFa>%1\n").arg(m_attenuation).toUtf8());
m_file.write(QString("<amCo>%1\n").arg(m_ambient).toUtf8());
if(!m_listOfDirs.isEmpty())
m_file.write(QString("<qkList>%1\n").arg(m_listOfDirs.join(";")).toUtf8());
m_file.close();
}
// getter ///////////////////////////////////////////////////////////////
QStringList SettingsManager::getListOfDirs()
{
return m_listOfDirs;
}
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;
}
void SettingsManager::updateDirectories(QString path)
{
if (m_listOfDirs.contains(path))
m_listOfDirs.removeAll(path);
else
m_listOfDirs.append(path);
emit dirsChanged();
}

View File

@@ -1,5 +1,10 @@
#include "..\Header\SettingsWindow.h" #include "..\Header\SettingsWindow.h"
#include <QString> #include "..\Header\SettingsManager.h"
#include <QFileDialog>
#include <QListWidgetItem>
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
SettingsWindow::SettingsWindow(QWidget * parent) SettingsWindow::SettingsWindow(QWidget * parent)
: QWidget(parent) : QWidget(parent)
@@ -9,50 +14,50 @@ SettingsWindow::SettingsWindow(QWidget * parent)
setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint); setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
// light off setupConnections();
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);
connect(ui->lightOff_G_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOff_G_S->setValue(value.toInt());}); // set default values
connect(ui->lightOff_G_S, &QSlider::valueChanged, [this](const int& value){ui->lightOff_G_LE->setText(QString::number(value));}); SettingsManager* sm = SettingsManager::getInstance(this);
connect(ui->lightOff_G_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
connect(ui->lightOff_B_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOff_B_S->setValue(value.toInt());}); // set dirList for passing to Main and then fill settings manager dir list window
connect(ui->lightOff_B_S, &QSlider::valueChanged, [this](const int& value){ui->lightOff_B_LE->setText(QString::number(value));}); QStringList tmp_directories = sm->getListOfDirs();
connect(ui->lightOff_B_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged); for (auto &it : tmp_directories)
ui->dirListWidget->insertItem(0, it);
// light on ui->lightOff_R_SB->setValue((int)(sm->getBgColorOff()[0]));
connect(ui->lightOn_R_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOn_R_S->setValue(value.toInt());}); ui->lightOff_G_SB->setValue((int)(sm->getBgColorOff()[1]));
connect(ui->lightOn_R_S, &QSlider::valueChanged, [this](const int& value){ui->lightOn_R_LE->setText(QString::number(value));}); ui->lightOff_B_SB->setValue((int)(sm->getBgColorOff()[2]));
connect(ui->lightOn_R_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
connect(ui->lightOn_G_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOn_G_S->setValue(value.toInt());}); ui->lightOn_R_SB->setValue((int)(sm->getBgColorOn()[0]));
connect(ui->lightOn_G_S, &QSlider::valueChanged, [this](const int& value){ui->lightOn_G_LE->setText(QString::number(value));}); ui->lightOn_G_SB->setValue((int)(sm->getBgColorOn()[1]));
connect(ui->lightOn_G_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged); ui->lightOn_B_SB->setValue((int)(sm->getBgColorOn()[2]));
connect(ui->lightOn_B_LE, &QLineEdit::textChanged, [this](const QString& value){ui->lightOn_B_S->setValue(value.toInt());}); ui->light_R_SB->setValue((int)(sm->getLightColor()[0]));
connect(ui->lightOn_B_S, &QSlider::valueChanged, [this](const int& value){ui->lightOn_B_LE->setText(QString::number(value));}); ui->light_G_SB->setValue((int)(sm->getLightColor()[1]));
connect(ui->lightOn_B_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged); ui->light_B_SB->setValue((int)(sm->getLightColor()[2]));
// light ui->ambCoef->setValue(sm->getAmbient());
connect(ui->light_R_LE, &QLineEdit::textChanged, [this](const QString& value){ui->light_R_S->setValue(value.toInt());}); ui->attFac->setValue(sm->getAttenuation());
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);
connect(ui->light_G_LE, &QLineEdit::textChanged, [this](const QString& value){ui->light_G_S->setValue(value.toInt());}); ui->checkBackfaceCulling->setChecked(sm->isBfCulling());
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));}); ui->checkAutoColor->setChecked(sm->isAutoColor());
connect(ui->light_G_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged); ui->checkHeadlight->setChecked(sm->isHeadlight());
connect(ui->light_B_LE, &QLineEdit::textChanged, [this](const QString& value){ui->light_B_S->setValue(value.toInt());}); if (sm->getLightType() == 1)
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));}); ui->radioDirectLight->setChecked(true);
connect(ui->light_B_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged); else
ui->radioPointLight->setChecked(true);
connect(this, &SettingsWindow::updateBGColorOff, sm, &SettingsManager::setBgColorOff);
connect(ui->checkAutoColor, &QCheckBox::toggled, this, &SettingsWindow::autoColorToggled); connect(this, &SettingsWindow::updateBGColorOn, sm, &SettingsManager::setBgColorOn);
connect(ui->radioDirectLight, &QRadioButton::toggled, this, &SettingsWindow::radioToggled); connect(this, &SettingsWindow::updateLightColor, sm, &SettingsManager::setLightColor);
connect(ui->ambCoef, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAmbCoef(value); }); connect(this, &SettingsWindow::updateAttFac, sm, &SettingsManager::setAttenuation);
connect(ui->attFac, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAttFac(value); }); 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(this, &SettingsWindow::pathChanged, sm, &SettingsManager::updateDirectories);
} }
SettingsWindow::~SettingsWindow() SettingsWindow::~SettingsWindow()
@@ -60,50 +65,104 @@ SettingsWindow::~SettingsWindow()
delete ui; 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() void SettingsWindow::autoColorToggled()
{ {
if (!ui->checkAutoColor->isChecked()) if (!ui->checkAutoColor->isChecked())
{ {
ui->lightOn_R_LE->setEnabled(true); ui->lightOn_R_SB->setEnabled(true);
ui->lightOn_R_S->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_G_S->setEnabled(true);
ui->lightOn_B_LE->setEnabled(true); ui->lightOn_B_SB->setEnabled(true);
ui->lightOn_B_S->setEnabled(true); ui->lightOn_B_S->setEnabled(true);
} }
else else
{ {
ui->lightOn_R_LE->setEnabled(false); ui->lightOn_R_SB->setEnabled(false);
ui->lightOn_R_S->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_G_S->setEnabled(false);
ui->lightOn_B_LE->setEnabled(false); ui->lightOn_B_SB->setEnabled(false);
ui->lightOn_B_S->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_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_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)); ui->lightOn_B_S->setValue((int)(ui->light_B_S->value() / 50));
} }
} }
void SettingsWindow::radioToggled() void SettingsWindow::radioToggled()
{ {
if(ui->radioDirectLight->isChecked()) if (ui->radioDirectLight->isChecked())
{ {
ui->attFac->setValue(0.0); ui->attFac->setValue(0.0);
ui->attFac->setEnabled(false); ui->attFac->setEnabled(false);
ui->ambCoef->setEnabled(false); emit changeLightType(1);
} }
else else
{ {
ui->attFac->setEnabled(true); ui->attFac->setEnabled(true);
ui->ambCoef->setEnabled(true); emit changeLightType(2);
} }
} }
@@ -120,5 +179,30 @@ void SettingsWindow::backgroundColorOnChanged()
void SettingsWindow::lightColorChanged() void SettingsWindow::lightColorChanged()
{ {
emit updateLightColor(QVector3D(ui->light_R_S->value(), ui->light_G_S->value(), ui->light_B_S->value())); 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));
}
} }
void SettingsWindow::on_addItem_clicked()
{
QString dirName = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home",
QFileDialog::ShowDirsOnly |
QFileDialog::DontResolveSymlinks);
if (!SettingsManager::getInstance()->getListOfDirs().contains(dirName))
{
ui->dirListWidget->insertItem(0, dirName);
emit pathChanged(dirName);
}
}
void SettingsWindow::on_removeItem_clicked()
{
QListWidgetItem* tmp = ui->dirListWidget->takeItem(ui->dirListWidget->currentRow());
emit pathChanged(tmp->text());
delete tmp;
}

View File

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

View File

@@ -12,10 +12,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 Feel free to use my code the way you like. But remember i used some public libraries. Make sure you read their
licence, too. 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