Compare commits

...

84 Commits

Author SHA1 Message Date
itdominator 64d5584698 Update 'README.md' 2021-04-26 21:07:42 +00:00
Anakin 7e87b14fe1 made all path relative now 2017-04-30 15:05:21 +02:00
Anakin da0b7e3c5f new release version,
Features:
- fixed overexposed specular bug,
- most settings are saved after each session
Bugs:
-nothing known
2017-02-08 14:32:48 +01:00
Anakin fa75e17d58 most settings are saved and restored 2017-02-08 14:29:22 +01:00
Anakin 49585945c3 fixed too high specular,
updated preview.jpg
2017-02-06 16:53:27 +01:00
Anakin 67657061b6 new release version,
Features:
- normal map support,
- added specular support for cloth,
- "glow" support,
Bugs:
- normal mapping looks a bit drizzly depending on the angle of view
2017-02-06 14:59:46 +01:00
Anakin 06d403d546 support normal map now,
support "glow" now,
update preview.jpg
2017-02-06 14:53:05 +01:00
Anakin 541a975624 added preview imange,
passed data to shader,
need to process data in shader
2017-02-05 20:10:05 +01:00
Anakin 30f1a1e627 passing poylNormal, tangent, bitangent to shader 2017-02-05 16:57:12 +01:00
Anakin cdf19911f6 calculate polygon normal, tangent, and bitangent,
next step, use them for calculation
2017-02-05 16:39:37 +01:00
Anakin 4c40d140a9 cloth now has specular 2017-02-05 15:25:59 +01:00
Anakin f47e1cc76a new release version,
Features:
- extreme performance improvement when loading files,
- new camera controls (free, orbital, move),
- using ogl 4.5 again since 2.0 causes problems on some pc,
Bugs:
- nothing known
2017-02-05 12:38:32 +01:00
Anakin 2d335474bf fixed camera control,
removed test exe
2017-02-05 12:34:24 +01:00
Anakin a07d8acbec update gui for camera mods 2017-02-04 17:42:44 +01:00
Anakin 800a6a50f8 doesn't work for ggctuk since i use ogl 2.0 instead of 4.5
trying to figure out the problem
2017-02-04 15:57:15 +01:00
Anakin 94a2fa59ec added MoveCamera but isn't working well
updated about text,
2017-02-04 15:48:10 +01:00
Anakin 648b805daf forget to save file 2017-02-03 15:55:04 +01:00
Anakin 92245be302 finished OrbitCamera 2017-02-03 15:54:45 +01:00
Anakin 333eca25eb use class for camera handling,
orbit does not work. Need to figure out why
2017-02-02 18:01:08 +01:00
Anakin b17ab3f8e9 fixed out of file check order 2017-02-02 15:26:40 +01:00
Anakin ff08ee7cea error handling when out of file 2017-02-02 15:10:48 +01:00
Anakin 8346e5916d changed everything from std to qt 2017-02-02 14:44:48 +01:00
Anakin 5372838420 further performance improvement 2017-02-02 11:14:16 +01:00
Anakin a14229aa71 further improvement on tga import 2017-02-01 17:53:42 +01:00
Anakin 1c5631a5e0 improve image load performance,
can be improved more, but scanline has wrong results
2017-02-01 17:41:29 +01:00
Anakin bc5bfc62bc fixed a bug 2017-02-01 16:34:43 +01:00
Anakin 4cb070c8c5 removed files from repo that are not needed in the release folder 2017-01-30 17:24:21 +01:00
Anakin 2d9c103c01 new release version,
Features:
- Headlight option,
- zoom speed now adjust in settings window, not via +/-,
- cullface can be activated in the settings,
- text in FileInfoWindow can be marked and copied,
- alpha channel now always used,
- fixed compatibility problems,
- code and performance improvements,
Bugs:
- nothing known
2017-01-30 17:10:41 +01:00
Anakin 37e9b86daa fixed bug that sometimes alpha channel was not read in,
code improvement = performance,
2017-01-30 16:54:35 +01:00
Anakin 4342260e6d improved performance using my own tga load function always instead of QImage
improved Profiler
2017-01-30 16:00:14 +01:00
Anakin d1c68e8ba6 added Profiler to analyses the time used by code lines 2017-01-30 12:01:45 +01:00
Anakin 9c16aa32f1 headlight,
bug fixes,
code improvement,
2017-01-30 11:31:37 +01:00
Anakin fbb51563c9 fixed backface culling bug,
todo: connect headligh
2017-01-30 00:02:32 +01:00
Anakin 538453c1db added headlight option to settings,
added cullface option to settings,
zoom speed now adjust at settings,
bugs:
cullface does not work anymore,
todo:
connect headlight
2017-01-29 23:47:14 +01:00
Anakin 7b739ab892 use OutputDevice to set fileinfo,
use new connect function,
2017-01-29 15:19:20 +01:00
Anakin 98302664ca add OuputDevice as singleton to manage output to statusbar, 2017-01-29 11:35:43 +01:00
Anakin 96b7d6f736 text in FileInfoWindow can be marked and copied,
code cleaning
2017-01-28 16:54:36 +01:00
Anakin 121f5c47f1 fixed some warnings 2017-01-26 19:44:12 +01:00
Anakin fe374cb8f6 made fshader.glsl compatible with older versions 2017-01-26 18:25:24 +01:00
Anakin fb49d8685a switch from QLineEdit to QSpinBox,
init SettingsWindow with default values from OglViewerWidget,
removed old qt project
2017-01-26 18:17:54 +01:00
Anakin 3167f1acb8 new release version,
Features:
- screenshot function,
- transparency support,
- wireframe paint option,
- support phong model (ambient, diffuse, specular),
- 2 different kinds of light (directional and point),
- different background colors for light on/off,
- zoom speed now adjustable via +/- keys,
- new file info window,
- more information displayed at the info window,
- settings window,
- new GUI,
- now openGl 2.0 is minimum (before 4.5)
- some more code changes, bug fixes, performance improvements,
Bugs:
- nothing known
2017-01-24 19:46:48 +01:00
Anakin 308d238b2d add settings icon,
set ogl verison to 2.0 to make it compatible with more PCs
2017-01-24 19:39:34 +01:00
Anakin 30d41f7d85 connected settings window with software 2017-01-24 17:09:51 +01:00
C-Fu 15cd551f7c forgot light - background connection 2017-01-24 11:55:00 +01:00
C-Fu 16c9d35580 Removed slots, I use lambda now 2017-01-24 11:48:45 +01:00
C-Fu 11af758eee use lambda expressions instead of slots 2017-01-24 11:40:38 +01:00
Anakin 73ee8a4040 added settings window,
connected all slider, lineEdits, checkboxes,...,
need to connect everything with the OglViewerWidget now
2017-01-23 16:09:06 +01:00
Anakin 0a9103fdc5 differ vertexNormal and triangleNormal 2017-01-23 13:49:29 +01:00
Anakin 10718f2269 load tx1d texture 2017-01-23 12:29:10 +01:00
Anakin b2df84eb4c read tx1d tx2d tx3d texture names and print to info window 2017-01-23 12:17:26 +01:00
Anakin 2ed9e475ce fixed white scrollbar at the info window 2017-01-23 11:57:23 +01:00
Anakin cdd6ace701 save rendertype,
evaluate rednertype specular,
changed info window always on top
2017-01-22 15:41:08 +01:00
Anakin 91488c55b2 more information for the InfoWindow,
set correct values for cloth material,
enable specular map
2017-01-22 14:37:06 +01:00
Anakin 5f104e46f2 gui changes 2017-01-22 12:25:59 +01:00
Anakin a948590255 fixed flag reading bug 2017-01-21 17:16:44 +01:00
Anakin 6fa81a8ccc Some styling 2017-01-21 16:33:03 +01:00
Anakin c4444bcefd fixed background bug,
support directional light,
zoom speed can be adjust via +/-
2017-01-21 15:22:43 +01:00
Anakin 5ea90723b4 changed intensity of background 2017-01-20 16:54:27 +01:00
Anakin af94ecd541 change background when the light is on 2017-01-20 16:39:17 +01:00
Anakin 9808cd03c0 save more material information,
hold default material in geometry separated,
load diffuse color if texture cannot be opened,
fixed gamma correction on the texture,
2017-01-20 16:26:58 +01:00
C-Fu abd9070e90 Read the material name and save it,
Shorten transparency evaluation,
Need to:
- read in the data values,
- save the texture name somewhere else,
- use the data :D
2017-01-20 11:18:48 +01:00
C-Fu eb0592373f added attributes to materials 2017-01-20 10:49:43 +01:00
Anakin 28d17b2fdd trying to workaround gamma correction (remove from tga) 2017-01-19 20:15:00 +01:00
Anakin 9fb3ca03bd added specular, ambient light,...
need to fix the texutre gamma correction,
look at the todos
2017-01-19 17:57:50 +01:00
Anakin 4c177f2ddc adjust light functionality,
bugs:
- background cannot be changed during runtime
2017-01-18 17:01:43 +01:00
Anakin a521dfc292 calculate normal matrix once in cpp (performance),
added bool variable to turn light on/off (still needs button),
2017-01-17 20:18:04 +01:00
Anakin f5863752e2 fixed the light problem,
very basic light at the moment, needs a lot of work:
- custom position,
- custom intensities,
- calculate at better positions,
others:
- adjust zoom speed
2017-01-17 18:03:47 +01:00
Anakin 1c962a481f implemented light into cpp,
bug:
everything is dark,
need to calculate the normal matrix once in cpp and not for every pixel
2017-01-17 17:48:54 +01:00
Anakin 86c0559fdc Merge branch 'master' of git.rwth-aachen.de:carstenf/OpenGL 2017-01-17 17:36:35 +01:00
C-Fu 1bcb4d67c1 fixed wrong dimension 2017-01-17 11:37:07 +01:00
C-Fu 152d436dd7 Calculate vertex position in world space in vertex shaded not in fragment 2017-01-17 11:36:23 +01:00
C-Fu 5191a46f72 Added light calculation to fragment shader 2017-01-17 11:32:06 +01:00
C-Fu 9b3ff7f737 adjust vertex shaded to pass information to fragment shaded for light 2017-01-17 11:15:30 +01:00
Anakin 91b3f25dbb fixed wireframe bug 2017-01-16 16:41:52 +01:00
Anakin 47c73ed881 added custom info window,
set min size to mainwindow
2017-01-16 15:41:37 +01:00
Anakin 86dfe32145 add wireframe paint option,
write file information on the screen,
bug fixes
2017-01-16 14:24:30 +01:00
Anakin 454ed45fa1 support transparency now 2017-01-15 15:51:12 +01:00
Anakin b8f8a5c2ad fixed the problem 2017-01-15 12:33:57 +01:00
Anakin 6ead5d7bc6 working on changing the texture names to materials,
problems with call by value/reference
2017-01-15 12:26:15 +01:00
Anakin f469dff656 added transparency support,
need to sort the transparent things to the back
2017-01-14 17:20:50 +01:00
Anakin 930c49e9c7 add screenshot function 2017-01-11 16:28:51 +01:00
Anakin 77ffe7baf4 added icons 2017-01-09 16:34:54 +01:00
Anakin e41b831047 new release version
Features:
- WinXP support
2017-01-09 10:34:24 +01:00
Anakin 948578f506 add normal to VertexData 2017-01-08 14:41:53 +01:00
105 changed files with 3391 additions and 2295 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

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FileInfoWindow</class>
<widget class="QWidget" name="FileInfoWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>File information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="basic">
<property name="text">
<string>Name: -
Materials: -
Vertices: -
Triangles: -</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>322</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="detail">
<property name="text">
<string>No file is open</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

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

View File

@ -0,0 +1,555 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsWindow</class>
<widget class="QWidget" name="SettingsWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>358</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBackground">
<property name="title">
<string>Background</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="5">
<widget class="QSpinBox" name="lightOn_G_SB">
<property name="enabled">
<bool>false</bool>
</property>
<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="4" column="7">
<widget class="QLabel" name="label_5">
<property name="text">
<string>B:</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QSlider" name="lightOn_G_S">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="9">
<widget class="QSlider" name="lightOn_B_S">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="3" colspan="3">
<widget class="QCheckBox" name="checkAutoColor">
<property name="text">
<string>auto color</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="8">
<widget class="QSpinBox" name="lightOn_B_SB">
<property name="enabled">
<bool>false</bool>
</property>
<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="2" column="0" colspan="2">
<widget class="QLabel" name="label_0">
<property name="text">
<string>R:</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLabel" name="label_1">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
<item row="2" column="7">
<widget class="QLabel" name="label_2">
<property name="text">
<string>B:</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QSpinBox" name="lightOff_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="2" column="8">
<widget class="QSpinBox" name="lightOff_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="2" column="9">
<widget class="QSlider" name="lightOff_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="2" column="2">
<widget class="QSpinBox" name="lightOff_R_SB">
<property name="enabled">
<bool>true</bool>
</property>
<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="2" column="6">
<widget class="QSlider" name="lightOff_G_S">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>204</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QSlider" name="lightOff_R_S">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>127</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="labelLightOn">
<property name="text">
<string>Light on:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="10">
<widget class="QLabel" name="labelLightOff">
<property name="text">
<string>Light off:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>R:</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QSpinBox" name="lightOn_R_SB">
<property name="enabled">
<bool>false</bool>
</property>
<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="4" column="3">
<widget class="QSlider" name="lightOn_R_S">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QLabel" name="label_4">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupLight">
<property name="title">
<string>Light</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="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="1" column="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QLabel" name="labelAttFac">
<property name="text">
<string>Attenuationfactor:</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="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="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="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="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="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">
<widget class="QDoubleSpinBox" name="ambCoef">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.005000000000000</double>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QSlider" name="light_G_S">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>255</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="labelAmbCoeff">
<property name="text">
<string>Ambientcoefficient:</string>
</property>
</widget>
</item>
<item row="0" column="7" colspan="2">
<widget class="QCheckBox" name="checkHeadlight">
<property name="text">
<string>Headlight</string>
</property>
</widget>
</item>
<item row="0" column="4" colspan="3">
<widget class="QRadioButton" name="radioPointLight">
<property name="text">
<string>Point light</string>
</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="1" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelZoomSpeed">
<property name="text">
<string>Zoom speed:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="spinZSpeed">
<property name="suffix">
<string>%</string>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QCheckBox" name="checkBackfaceCulling">
<property name="text">
<string>Backface Culling</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

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

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

View File

@ -1,15 +1,11 @@
#pragma once
#include <fstream>
#include <QOpenGlTexture>
#include <QFile>
#include <QVector>
#include <QVector2D>
#include <QVector3D>
#include <QStringList>
#include <QMatrix4x4>
#include <QQuaternion>
#include <QOpenGLFunctions>
#include <QObject>
#include <..\Header\MainWindow.h>
#include <QRegExp>
struct BoundingBox {
QQuaternion rotation;
@ -21,42 +17,59 @@ struct VertexData
{
QVector3D position;
QVector2D texCoord;
QVector3D vertexNormal;
QVector3D polygonNormal;
QVector3D tangent;
QVector3D bitangent;
};
struct Segment {
std::uint32_t textureIndex = 0;
quint32 textureIndex = 0;
QVector<VertexData> vertices;
QVector<GLuint> indices;
};
struct Model {
std::string name = "";
std::string parent = "";
QString name = "";
QString parent = "";
QMatrix4x4 m4x4Translation;
QQuaternion quadRotation;
std::vector<Segment*> segmList;
QVector<Segment*> segmList;
};
class FileInterface : public QObject
struct Material {
QString name;
QString tx0d;
QString tx1d;
QString tx2d;
QString tx3d;
QOpenGLTexture* texture0 = Q_NULLPTR;
QOpenGLTexture* texture1 = Q_NULLPTR;
QVector4D specularColor = { 0.1f, 0.1f, 0.1f, 1.0 };
QVector4D diffuseColor = { 1.0, 0.0, 0.0, 1.0 };
QVector4D ambientColor = { 1.0, 1.0, 1.0, 1.0 };
float shininess = 1;
bool flags[8] = { false };
bool transparent = false;
quint8 rendertype = 0;
quint8 dataValues[2] = { 0 };
};
class FileInterface
{
Q_OBJECT
public:
explicit FileInterface(QString path, QObject *parent)
: QObject(parent)
, m_models(new QVector<Model*>)
, m_textureNames(new QStringList)
explicit FileInterface(QString path)
: m_models(new QVector<Model*>)
, m_materials(new QVector<Material>)
{
//open file
m_file.open(path.toStdString().c_str(), std::ios::in | std::ios::binary);
m_file.setFileName(path);
if (!m_file.is_open())
if (!m_file.open(QIODevice::ReadOnly))
throw std::invalid_argument(std::string("ERROR: file not found: ") += path.toStdString());
MainWindow* tmp = dynamic_cast<MainWindow*>(parent->parent()->parent());
if(tmp != NULL)
connect(this, SIGNAL(sendMessage(QString, int)), tmp, SLOT(printMessage(QString, int)));
m_filepath = path.left(path.lastIndexOf(QRegExp("/|\\\\")));
};
@ -66,9 +79,6 @@ public:
m_file.close();
//clean up
m_textureNames->clear();
delete m_textureNames;
for (Model* modelIt : *m_models)
{
for (Segment* segIt : modelIt->segmList)
@ -87,17 +97,40 @@ public:
protected:
QVector<Model*>* m_models;
std::fstream m_file;
QStringList* m_textureNames;
QFile m_file;
QVector<Material>* m_materials;
BoundingBox m_sceneBbox;
QString m_filepath;
virtual void import() = 0;
public:
virtual QVector<Model*>* getModels() const { return m_models; };
virtual QStringList* getTextureNames() const { return m_textureNames; };
virtual QVector<Material>* getMaterials() const { return m_materials; };
virtual BoundingBox getBoundingBox() const { return m_sceneBbox; };
signals:
void sendMessage(QString msg, int severity);
static Material* getDefaultMaterial() {
Material* defMaterial = new Material;
QImage img(1, 1, QImage::Format_RGB32);
img.fill(Qt::red);
QOpenGLTexture* new_texture = new QOpenGLTexture(img.mirrored());
// Set nearest filtering mode for texture minification
new_texture->setMinificationFilter(QOpenGLTexture::Nearest);
// Set bilinear filtering mode for texture magnification
new_texture->setMagnificationFilter(QOpenGLTexture::Linear);
// Wrap texture coordinates by repeating
// f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
new_texture->setWrapMode(QOpenGLTexture::Repeat);
defMaterial->texture0 = new_texture;
defMaterial->name = "Default Material";
return defMaterial;
};
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,38 @@
#pragma once
#include <QWidget>
#include "ui_SettingsWindow.h"
#include <QVector3D>
class SettingsWindow : public QWidget
{
Q_OBJECT
public:
SettingsWindow(QWidget * parent = Q_NULLPTR);
~SettingsWindow();
private:
Ui::SettingsWindow* ui;
void setupConnections();
private slots:
void autoColorToggled();
void radioToggled();
void backgroundColorOffChanged();
void backgroundColorOnChanged();
void lightColorChanged();
signals:
void updateBGColorOff(QVector3D value);
void updateBGColorOn(QVector3D value);
void updateLightColor(QVector3D value);
void updateAttFac(double value);
void updateAmbCoef(double value);
void sendHeadlight(bool value);
void sendBackfaceCulling(bool value);
void sendZommSpeed(int percent);
void changeLightType(int value);
};

View File

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

View File

@ -8,5 +8,21 @@
</qresource>
<qresource prefix="/files">
<file>about.txt</file>
<file>StyleSheet.txt</file>
</qresource>
<qresource prefix="/images/toolbar">
<file>placeholder.png</file>
<file>info.png</file>
<file>about.png</file>
<file>open.png</file>
<file>screenshot.png</file>
<file>wireframe.png</file>
<file>light_off.png</file>
<file>light_on.png</file>
<file>solid.png</file>
<file>settings.png</file>
<file>freeCamera.png</file>
<file>orbitalCamera.png</file>
<file>walkCamera.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,79 @@
QLabel#output {
color : white;
min-width: 400px;
min-height: 50px;
}
QToolButton {
image: url(:/images/toolbar/placeholder.png);
border-style: none;
padding: 2px;
width: 22px;
height: 22px;
}
QToolButton:checked {
image: url(:/images/toolbar/placeholder.png);
border-style: none;
padding: 2px;
width: 22px;
height: 22px;
}
QToolButton:hover {
border-style: solid;
padding: 1px;
border-width: 1px;
border-radius: 5px;
border-color: #a4daff;
min-height: 25px
}
QToolButton#openFile {
image: url(:/images/toolbar/open.png);
}
QToolButton#screenshot {
image: url(:/images/toolbar/screenshot.png);
}
QToolButton#freeCamera {
image: url(:/images/toolbar/freeCamera.png);
}
QToolButton#orbitalCamera {
image: url(:/images/toolbar/orbitalCamera.png);
}
QToolButton#walkCamera {
image: url(:/images/toolbar/walkCamera.png);
}
QToolButton#wireframe {
image: url(:/images/toolbar/solid.png);
}
QToolButton#wireframe:checked {
image: url(:/images/toolbar/wireframe.png);
}
QToolButton#light {
image: url(:/images/toolbar/light_off.png);
}
QToolButton#light:checked {
image: url(:/images/toolbar/light_on.png);
}
QToolButton#settings {
image: url(:/images/toolbar/settings.png);
}
QToolButton#fileInfo {
image: url(:/images/toolbar/info.png);
}
QToolButton#help {
image: url(:/images/toolbar/about.png);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

View File

@ -4,16 +4,32 @@ source code: https://git.rwth-aachen.de/carstenf/OpenGL/tree/master/QtMeshViewer
===============================================================
Controll:
Free Camera: static view position and you rotate and move the object
left mouse - rotate
right mouse - move
scroll - zoom
Orbit Camera: static object and you move around it like a satalite
left mouse - rotate
scroll - zoom
Move Camera: static object and you can walk through the scene
w/s - forward/backward
a/d - left/right
left mouse - look around
General:
space - reset view
L - set light to current position
esc - close
using the X, Y, Z Button you can activate/deactivate the rotating directions
using the X, Y, Z buttons you can activate/deactivate the rotating directions.
tipp: do round movement to rotate the object in z-direction, when all directions are acitvated
textures marked with a '*' couldn't be open.
===============================================================
Credits:
ANDEWEGET

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 940 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

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,17 +2,17 @@
#include "..\Header\MshFile.h"
#include "..\Header\OglViewerWidget.h"
#include "..\Header\MainWindow.h"
#include "..\Header\tga.h"
#include <cmath>
#include "..\Header\OutputDevice.h"
#include <QRegExp>
/////////////////////////////////////////////////////////////////////////
// public constructor/destructor
// constructor/destructor
GeometryEngine::GeometryEngine(QObject *parent)
: QObject(parent)
, m_indexBuf(QOpenGLBuffer::IndexBuffer)
, m_defaultMaterial(FileInterface::getDefaultMaterial())
{
initializeOpenGLFunctions();
}
@ -20,44 +20,13 @@ GeometryEngine::GeometryEngine(QObject *parent)
GeometryEngine::~GeometryEngine()
{
clearData();
delete m_defaultMaterial->texture0;
delete m_defaultMaterial;
}
/////////////////////////////////////////////////////////////////////////
// private functions
void GeometryEngine::loadTexture(QString filePath, QString fileName)
{
bool loadSuccess(false);
QImage img;
if (fileName.isEmpty())
{
loadSuccess = true;
img = QImage(1, 1, QImage::Format_RGB32);
img.fill(Qt::red);
}
else
img = loadTga(filePath + "/" + fileName, loadSuccess);
if (!loadSuccess)
emit sendMessage("WARNING: texture not found or corrupted: " + QString(fileName), 1);
// Load image to OglTexture
QOpenGLTexture* new_texture = new QOpenGLTexture(img.mirrored());
// Set nearest filtering mode for texture minification
new_texture->setMinificationFilter(QOpenGLTexture::Nearest);
// Set bilinear filtering mode for texture magnification
new_texture->setMagnificationFilter(QOpenGLTexture::Linear);
// Wrap texture coordinates by repeating
// f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
new_texture->setWrapMode(QOpenGLTexture::Repeat);
m_textures.push_back(new_texture);
}
// functions
void GeometryEngine::clearData()
{
@ -66,15 +35,155 @@ void GeometryEngine::clearData()
if (m_indexBuf.isCreated())
m_indexBuf.destroy();
for (auto it : m_textures)
delete it;
m_textures.clear();
if (m_materials != Q_NULLPTR)
{
for (auto it : *m_materials)
{
if (it.texture0 != Q_NULLPTR)
delete it.texture0;
if (it.texture1 != Q_NULLPTR)
delete it.texture1;
}
m_materials->clear();
delete m_materials;
}
m_drawList.clear();
}
void GeometryEngine::setupPipeline(QOpenGLShaderProgram *program)
{
// Offset for position
quintptr offset = 0;
/////////////////////////////////////////////////////////////////////////
// public slots
// Tell OpenGL programmable pipeline how to locate vertex position data
int vertexLocation = program->attributeLocation("a_position");
program->enableAttributeArray(vertexLocation);
program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
// Offset for texture coordinate
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
int texcoordLocation = program->attributeLocation("a_texcoord");
program->enableAttributeArray(texcoordLocation);
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
//Offset for vertexNormal
offset += sizeof(QVector2D);
// Tell OpenGL programmable pipeline how to locate vertex normal data
int vertNormLocation = program->attributeLocation("a_normal");
program->enableAttributeArray(vertNormLocation);
program->setAttributeBuffer(vertNormLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
//Offset for polygonNormal
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate polygon normal data
int polyNormLocation = program->attributeLocation("a_polyNorm");
program->enableAttributeArray(polyNormLocation);
program->setAttributeBuffer(polyNormLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
//Offset for polygonTangent
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate polygon tangent data
int polyTanLocation = program->attributeLocation("a_polyTan");
program->enableAttributeArray(polyTanLocation);
program->setAttributeBuffer(polyTanLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
//Offset for polygonBitangent
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate polygon bitangent data
int polyBiTanLocation = program->attributeLocation("a_polyBiTan");
program->enableAttributeArray(polyBiTanLocation);
program->setAttributeBuffer(polyBiTanLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
}
void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program)
{
if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated())
return;
// Setup
// Tell OpenGL which VBOs to use
m_arrayBuf.bind();
m_indexBuf.bind();
// Allways normalize by this
QMatrix4x4 normMatrix;
float maxExtent = std::max(std::max(m_boundings.extents[0], m_boundings.extents[1]), m_boundings.extents[2]);
normMatrix.scale(1 / maxExtent);
normMatrix.translate(-m_boundings.center[0], -m_boundings.center[1], -m_boundings.center[2]);
program->setUniformValue("normalizeModel", normMatrix);
// Allways use texture unit 0 and 1
program->setUniformValue("tx0", 0);
program->setUniformValue("tx1", 1);
//setup the pipeline
setupPipeline(program);
// Paint
for (auto& it : m_drawList)
{
bool tmp_transparent(false);
bool tmp_specular(false);
bool tmp_normalmap(false);
bool tmp_glow(false);
float shininess(0.0);
QVector3D specularColor;
// bind the correct texture
if (it.textureIndex < (unsigned)m_materials->size() && m_materials->at(it.textureIndex).texture0 != Q_NULLPTR)
{
m_materials->at(it.textureIndex).texture0->bind(0);
tmp_transparent = m_materials->at(it.textureIndex).transparent;
tmp_specular = m_materials->at(it.textureIndex).flags[7];
shininess = m_materials->at(it.textureIndex).shininess;
specularColor = m_materials->at(it.textureIndex).specularColor.toVector3D();
if (m_materials->at(it.textureIndex).rendertype == 27 || m_materials->at(it.textureIndex).rendertype == 28)
{
if (m_materials->at(it.textureIndex).texture1 != Q_NULLPTR)
{
tmp_normalmap = true;
m_materials->at(it.textureIndex).texture1->bind(1);
}
}
if (m_materials->at(it.textureIndex).flags[0] || m_materials->at(it.textureIndex).flags[1] || m_materials->at(it.textureIndex).rendertype == 1)
tmp_glow = true;
}
else
{
m_defaultMaterial->texture0->bind(0);
tmp_transparent = m_defaultMaterial->transparent;
}
// Set model matrix
program->setUniformValue("modelMatrix", it.modelMatrix);
// Set normal matrix
program->setUniformValue("normalMatrix", (normMatrix * it.modelMatrix).normalMatrix());
// set some material attributes
program->setUniformValue("material.shininess", shininess);
program->setUniformValue("material.specularColor", specularColor);
program->setUniformValue("material.isTransparent", tmp_transparent);
program->setUniformValue("material.hasSpecularmap", tmp_specular);
program->setUniformValue("material.hasNormalmap", tmp_normalmap);
program->setUniformValue("material.isGlow", tmp_glow);
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint)));
}
}
void GeometryEngine::loadFile(QString filePath)
{
@ -85,20 +194,19 @@ void GeometryEngine::loadFile(QString filePath)
//reset view
emit requestResetView();
emit sendMessage("loading file..", 0);
OutputDevice::getInstance()->print("loading file..", 0);
try
{
QVector<Model*>* models;
QStringList* textureNames;
QVector<VertexData> vertexData;
QVector<GLuint> indexData;
// open file and get the information
MshFile file(filePath, this);
MshFile file(filePath);
models = file.getModels();
textureNames = file.getTextureNames();
m_materials = file.getMaterials();
m_boundings = file.getBoundingBox();
// collect data
@ -124,7 +232,11 @@ void GeometryEngine::loadFile(QString filePath)
// save data
vertexData += segmentIterator->vertices;
indexData += segmentIterator->indices;
m_drawList.push_back(new_info);
if (segmentIterator->textureIndex < (unsigned) m_materials->size() && m_materials->at(segmentIterator->textureIndex).transparent)
m_drawList.push_back(new_info);
else
m_drawList.push_front(new_info);
// update offset
indexOffset += new_info.size;
@ -140,77 +252,14 @@ void GeometryEngine::loadFile(QString filePath)
m_indexBuf.bind();
m_indexBuf.allocate(indexData.data(), indexData.size() * sizeof(GLuint));
emit sendMessage("loading textures..", 0);
// load the textures
int split = filePath.lastIndexOf(QRegExp("/|\\\\"));
for (auto& it : *textureNames)
loadTexture(filePath.left(split), it);
loadTexture("", "");
emit requestUpdate();
emit sendMessage("done..", 0);
emit sendFileInfo(filePath.right(filePath.size() - split - 1), QStringList(*textureNames), vertexData.size(), indexData.size() / 3);
OutputDevice::getInstance()->print("done..", 0);
OutputDevice::getInstance()->setFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3);
}
catch (std::invalid_argument e)
{
clearData();
emit sendMessage(QString(e.what()), 2);
}
}
void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program)
{
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));
// Paint
for (auto& it : m_drawList)
{
// bind the correct texture
if (it.textureIndex < m_textures.size())
m_textures.at(it.textureIndex)->bind();
else
m_textures.last()->bind();
// Set model matrix
program->setUniformValue("m_matrix", it.modelMatrix);
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint)));
OutputDevice::getInstance()->print(QString(e.what()), 2);
}
}

View File

@ -1,41 +1,193 @@
#include "..\Header\MainWindow.h"
#include "..\Header\OglViewerWidget.h"
#include <QSurfaceFormat>
#include <QMessageBox>
#include <QFileDialog>
#include <QPalette>
#include <QAction>
#include <QSignalMapper>
#include <QFile>
#include <QSizePolicy>
#include "..\Header\FileInterface.h"
#include "..\Header\OutputDevice.h"
#include <QSurfaceFormat>
#include <QSignalMapper>
#include <QToolButton>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QPalette>
#include <QResizeEvent>
#define WINDOW_NAME "Mesh Viewer"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindowClass)
, m_output(new QLabel(this))
, m_curSeverity(0)
, m_infoWindow(new FileInfoWindow(this))
{
// setup window
ui->setupUi(this);
setWindowTitle(WINDOW_NAME);
setWindowIcon(QIcon(":/images/icon.ico"));
connect(OutputDevice::getInstance(this), &OutputDevice::sendMessage, this, &MainWindow::printMessage);
connect(OutputDevice::getInstance(this), &OutputDevice::sendFileInfo, this, &MainWindow::setFileInfo);
// setup opengl things
QSurfaceFormat format;
format.setDepthBufferSize(24);
QSurfaceFormat::setDefaultFormat(format);
// set default text to file info
m_fileInfo = "Filename: -\nMaterials: -\nVertices: -\nTriangle: -<detail>No file is open";
// add widgets to the window
setupWidgets();
ui->statusBar->showMessage("MeshViewer by Anakin", 0);
// load stylesheet
QFile styleSheet(":/files/StyleSheet.txt");
styleSheet.open(QIODevice::ReadOnly);
this->setStyleSheet(styleSheet.readAll());
m_fileInfo += "Filename: -\nMaterials: -\nVertices: -\nTriangle: -\n<detail>No file is open";
getAssetLibrary();
printMessage("MeshViewer by Anakin", 0);
}
MainWindow::~MainWindow()
{
delete ui;
delete m_output;
delete m_infoWindow;
}
/////////////////////////////////////////////////////////////////////////
// functions
void MainWindow::setupWidgets()
{
// Ogl Viewer
OglViewerWidget* viewer = new OglViewerWidget(this);
setCentralWidget(viewer);
connect(this, &MainWindow::loadFile, viewer, &OglViewerWidget::loadFile);
// open file
QToolButton *openFile = new QToolButton(this);
openFile->setObjectName("openFile");
openFile->setToolTip("open file");
connect(openFile, &QToolButton::pressed, this, &MainWindow::openFile);
ui->mainToolBar->addWidget(openFile);
// screenshot
QToolButton *screenshot = new QToolButton(this);
screenshot->setObjectName("screenshot");
screenshot->setToolTip("take screenshot");
connect(screenshot, &QToolButton::pressed, this, &MainWindow::takeScreenShot);
ui->mainToolBar->addWidget(screenshot);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator();
// 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);
// Orbital Camera
QToolButton *orbitCamera = new QToolButton(this);
orbitCamera->setObjectName("orbitalCamera");
orbitCamera->setToolTip("orbital camera");
connect(orbitCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useOrbitCamera);
ui->mainToolBar->addWidget(orbitCamera);
// Move Camera
QToolButton *walkCamera = new QToolButton(this);
walkCamera->setObjectName("walkCamera");
walkCamera->setToolTip("walk camera");
connect(walkCamera, &QToolButton::pressed, viewer, &OglViewerWidget::useMoveCamera);
ui->mainToolBar->addWidget(walkCamera);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator();
// wireframe
QToolButton *wireframe = new QToolButton(this);
wireframe->setObjectName("wireframe");
wireframe->setToolTip("wireframe");
wireframe->setCheckable(true);
wireframe->setChecked(false);
connect(wireframe, &QToolButton::pressed, viewer, &OglViewerWidget::toggleWireframe);
ui->mainToolBar->addWidget(wireframe);
// light
QToolButton *light = new QToolButton(this);
light->setObjectName("light");
light->setToolTip("toggle light");
light->setCheckable(true);
light->setChecked(false);
connect(light, &QToolButton::pressed, viewer, &OglViewerWidget::toggleLight);
ui->mainToolBar->addWidget(light);
// settings
QToolButton *settings = new QToolButton(this);
settings->setObjectName("settings");
settings->setToolTip("settings");
connect(settings, &QToolButton::pressed, viewer, &OglViewerWidget::showSettings);
ui->mainToolBar->addWidget(settings);
//////////////////////////////////////////////////
ui->mainToolBar->addSeparator();
// fileinfo
QToolButton *fileInfo = new QToolButton(this);
fileInfo->setObjectName("fileInfo");
fileInfo->setToolTip("file info");
connect(fileInfo, &QToolButton::pressed, m_infoWindow, &FileInfoWindow::show);
ui->mainToolBar->addWidget(fileInfo);
// help
QToolButton *help = new QToolButton(this);
help->setObjectName("help");
help->setToolTip("help");
connect(help, &QToolButton::pressed, this, &MainWindow::aboutTool);
ui->mainToolBar->addWidget(help);
// output on screen
m_output->setObjectName("output");
m_output->setAlignment(Qt::AlignTop);
m_output->setText(m_fileInfo.left(m_fileInfo.indexOf("<detail>")));
m_output->raise();
}
void MainWindow::getAssetLibrary()
{
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setData(0, Qt::DisplayRole, "Wuhu");
ui->treeWidget->addTopLevelItem(item);
searchMeshFiles("D:/workspaces/Visual Studio 2015/Projects/OpenGL/Release");
}
void MainWindow::searchMeshFiles(QString path)
{
QDir directory(path);
directory.setNameFilters(QStringList("*.msh"));
QStringList childDirectories = directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
QStringList fileNames = directory.entryList(QDir::Files);
for (auto &it : childDirectories)
qDebug() << it;
for (auto &it : fileNames)
qDebug() << it;
}
void MainWindow::openFile()
@ -45,67 +197,13 @@ void MainWindow::openFile()
emit loadFile(fileName);
}
void MainWindow::setupWidgets()
void MainWindow::takeScreenShot()
{
OglViewerWidget* viewer = new OglViewerWidget(this);
setCentralWidget(viewer);
QString destination = QFileDialog::getSaveFileName(this, "Save as...", "", "PNG (*.png);; BMP (*.bmp);;TIFF (*.tiff, *.tif);;JPEG (*.jpg *jpeg)");
QAction *openFile = new QAction("Open file", this);
connect(openFile, &QAction::triggered, this, &MainWindow::openFile);
ui->mainToolBar->addAction(openFile);
QSignalMapper* signalMapper = new QSignalMapper(this);
QAction *x = new QAction("X", this);
x->setCheckable(true);
x->setChecked(true);
ui->mainToolBar->addAction(x);
QAction *y = new QAction("Y", this);
y->setCheckable(true);
y->setChecked(true);
ui->mainToolBar->addAction(y);
QAction *z = new QAction("Z", this);
z->setCheckable(true);
z->setChecked(true);
ui->mainToolBar->addAction(z);
connect(x, SIGNAL(triggered()), signalMapper, SLOT(map()));
connect(y, SIGNAL(triggered()), signalMapper, SLOT(map()));
connect(z, SIGNAL(triggered()), signalMapper, SLOT(map()));
signalMapper->setMapping(x, 1);
signalMapper->setMapping(y, 2);
signalMapper->setMapping(z, 3);
connect(signalMapper, SIGNAL(mapped(int)), viewer, SLOT(changeDirection(int)));
QAction *fileInfo = new QAction("File info", this);
connect(fileInfo, &QAction::triggered, this, &MainWindow::aboutFile);
ui->mainToolBar->addAction(fileInfo);
QAction *help = new QAction("Help", this);
connect(help, &QAction::triggered, this, &MainWindow::aboutTool);
ui->mainToolBar->addAction(help);
}
void MainWindow::aboutFile()
{
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;}");
dialog->setDetailedText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("<detail>") - 8)));
dialog->exec();
delete dialog;
OglViewerWidget* viewer = dynamic_cast<OglViewerWidget*>(centralWidget());
if (!destination.isEmpty() && viewer != NULL)
viewer->grab().save(destination);
}
void MainWindow::aboutTool()
@ -127,29 +225,15 @@ void MainWindow::aboutTool()
delete dialog;
}
void MainWindow::setFileInfo(QString name, QStringList textures, int vertices, int triangle)
void MainWindow::resizeEvent(QResizeEvent * e)
{
m_fileInfo = QByteArray("Filename: ");
m_fileInfo += name;
m_fileInfo += "\nMaterials: ";
m_fileInfo += QByteArray::number(textures.size());
m_fileInfo += "\nVertices: ";
m_fileInfo += QByteArray::number(vertices);
m_fileInfo += "\nTriangle: ";
m_fileInfo += QByteArray::number(triangle);
m_fileInfo += "<detail>";
int count(0);
for (auto& it : textures)
{
m_fileInfo += "Material ";
m_fileInfo += QByteArray::number(count++);
m_fileInfo += " - ";
m_fileInfo += it;
m_fileInfo += "\n";
}
m_output->move(40, e->size().height() - 80);
}
/////////////////////////////////////////////////////////////////////////
// slots
void MainWindow::printMessage(QString message, int severity)
{
if (!ui->statusBar->currentMessage().isEmpty() && severity < m_curSeverity)
@ -178,4 +262,115 @@ void MainWindow::printMessage(QString message, int severity)
ui->statusBar->setPalette(palette);
ui->statusBar->showMessage(message, time);
}
}
void MainWindow::setFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle)
{
// save basic file information
m_fileInfo = QByteArray("Filename: ");
m_fileInfo += name;
m_fileInfo += "\nMaterials: ";
m_fileInfo += QByteArray::number(materials->size());
m_fileInfo += "\nVertices: ";
m_fileInfo += QByteArray::number(vertices);
m_fileInfo += "\nTriangle: ";
m_fileInfo += QByteArray::number(triangle);
m_fileInfo += "<detail>";
// add detailed information
for (auto& it : *materials)
{
m_fileInfo += it.name;
m_fileInfo += "\n";
m_fileInfo += "TX0D:\t\t";
if (it.tx0d.isEmpty())
m_fileInfo += "-";
else
m_fileInfo += it.tx0d;
m_fileInfo += "\n";
m_fileInfo += "TX1D:\t\t";
if (it.tx1d.isEmpty())
m_fileInfo += "-";
else
m_fileInfo += it.tx1d;
m_fileInfo += "\n";
m_fileInfo += "TX2D:\t\t";
if (it.tx2d.isEmpty())
m_fileInfo += "-";
else
m_fileInfo += it.tx2d;
m_fileInfo += "\n";
m_fileInfo += "TX3D:\t\t";
if (it.tx3d.isEmpty())
m_fileInfo += "-";
else
m_fileInfo += it.tx3d;
m_fileInfo += "\n";
m_fileInfo += "Flags:\t\t";
for (int i = 0; i < 8; i++)
{
if (it.flags[i])
m_fileInfo += "1";
else
m_fileInfo += "0";
}
m_fileInfo += "\n";
m_fileInfo += "Rendertype:\t";
m_fileInfo += QByteArray::number(it.rendertype);
m_fileInfo += "\n";
m_fileInfo += "Gloss:\t";
m_fileInfo += QByteArray::number(it.shininess);
m_fileInfo += "\tData0:\t";
m_fileInfo += QByteArray::number(it.dataValues[0]);
m_fileInfo += "\tData1:\t";
m_fileInfo += QByteArray::number(it.dataValues[1]);
m_fileInfo += "\n";
m_fileInfo += "Diffusecolor:\tR: ";
m_fileInfo += QByteArray::number(it.diffuseColor.x());
m_fileInfo += "\tG: ";
m_fileInfo += QByteArray::number(it.diffuseColor.y());
m_fileInfo += "\tB: ";
m_fileInfo += QByteArray::number(it.diffuseColor.z());
m_fileInfo += "\tA: ";
m_fileInfo += QByteArray::number(it.diffuseColor.w());
m_fileInfo += "\n";
m_fileInfo += "Ambientcolor:\tR: ";
m_fileInfo += QByteArray::number(it.ambientColor.x());
m_fileInfo += "\tG: ";
m_fileInfo += QByteArray::number(it.ambientColor.y());
m_fileInfo += "\tB: ";
m_fileInfo += QByteArray::number(it.ambientColor.z());
m_fileInfo += "\tA: ";
m_fileInfo += QByteArray::number(it.ambientColor.w());
m_fileInfo += "\n";
m_fileInfo += "Specularcolor:\tR: ";
m_fileInfo += QByteArray::number(it.specularColor.x());
m_fileInfo += "\tG: ";
m_fileInfo += QByteArray::number(it.specularColor.y());
m_fileInfo += " \tB: ";
m_fileInfo += QByteArray::number(it.specularColor.z());
m_fileInfo += " \tA: ";
m_fileInfo += QByteArray::number(it.specularColor.w());
m_fileInfo += "\n";
m_fileInfo += "-----------------------------------------------------------------\n";
}
// print basic information on screen
m_output->setText(m_fileInfo.left(m_fileInfo.indexOf("<detail>")));
// print basic and detailed information on info window
m_infoWindow->setBasicText(QString(m_fileInfo.left(m_fileInfo.indexOf("<detail>"))));
m_infoWindow->setDetailText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("<detail>") - 8)));
}

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,4 +1,7 @@
#include "..\Header\MshFile.h"
#include "..\Header\tga.h"
#include "..\Header\OutputDevice.h"
#include <QVector3D>
// helper function to save data from file to any variable type
@ -8,8 +11,8 @@
/////////////////////////////////////////////////////////////////////////
// public constructor/destructor
MshFile::MshFile(QString path, QObject * parent)
: FileInterface(path, parent)
MshFile::MshFile(QString path)
: FileInterface(path)
{
import();
}
@ -25,22 +28,22 @@ MshFile::~MshFile()
void MshFile::import()
{
// go to file size information
m_file.seekg(4);
m_file.seek(4);
std::uint32_t tmp_fileSize;
std::list<ChunkHeader*> tmp_mainChunks;
quint32 tmp_fileSize;
QList<ChunkHeader*> tmp_mainChunks;
// get all chunks under HEDR
m_file.read(F2V(tmp_fileSize), sizeof(tmp_fileSize));
loadChunks(tmp_mainChunks, m_file.tellg(), tmp_fileSize);
loadChunks(tmp_mainChunks, m_file.pos(), tmp_fileSize);
// evaulate HEDR subchunks (= find MSH2)
for (ChunkHeader* it : tmp_mainChunks)
{
if (!strcmp("MSH2", it->name))
if ("MSH2" == it->name)
{
// get all subchunks
std::list<ChunkHeader*> tmp_msh2Chunks;
QList<ChunkHeader*> tmp_msh2Chunks;
loadChunks(tmp_msh2Chunks, it->position, it->size);
// evaluate MSH2 subchunks
@ -65,54 +68,57 @@ void MshFile::import()
}
}
void MshFile::loadChunks(std::list<ChunkHeader*>& destination, std::streampos start, const std::uint32_t length)
void MshFile::loadChunks(QList<ChunkHeader*>& destination, qint64 start, const quint32 length)
{
// jump to first chunk
m_file.seekg(start);
m_file.seek(start);
do
{
// out of file. Maybe a size information is corrupted
if (m_file.atEnd() || m_file.error() != QFileDevice::NoError)
{
OutputDevice::getInstance()->print("WARNING: corrupted file. Trying to continue..", 1);
m_file.unsetError();
m_file.seek(0);
break;
}
ChunkHeader* tmp_header = new ChunkHeader();
// get information
m_file.read(F2V(tmp_header->name[0]), sizeof(tmp_header->name) - 1);
char tmpName[5] = { 0 };
m_file.read(F2V(tmpName[0]), sizeof(tmpName) -1);
tmp_header->name = QString(tmpName);
m_file.read(F2V(tmp_header->size), sizeof(tmp_header->size));
tmp_header->position = m_file.tellg();
tmp_header->position = m_file.pos();
// store information
destination.push_back(tmp_header);
// jump to next header
m_file.seekg(tmp_header->size, std::ios_base::cur);
m_file.seek(tmp_header->size + m_file.pos());
// out of file. Maybe a size information is corrupted
if (!m_file.good())
{
emit sendMessage("WARNING: corrupted file. Trying to continue..", 1);
m_file.clear();
break;
}
} while (m_file.tellg() - start != length);
} while (m_file.pos() - start != length);
}
void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
void MshFile::analyseMsh2Chunks(QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// scene information
if (!strcmp("SINF", it->name))
if ("SINF" == it->name)
{
// get SINF subchunks
std::list<ChunkHeader*> tmp_sinfChunks;
QList<ChunkHeader*> tmp_sinfChunks;
loadChunks(tmp_sinfChunks, it->position, it->size);
// evaluate SINF subchunks
for (auto& it : tmp_sinfChunks)
{
if (!strcmp("BBOX", it->name))
if ("BBOX" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
// read in the quaternion
float tmp_quat[4];
@ -140,27 +146,28 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
}
// material list
else if (!strcmp("MATL", it->name))
else if ("MATL" == it->name)
{
OutputDevice::getInstance()->print("loading materials..", 0);
// "useless" information how many MATD follow, jump over it
m_file.seekg(it->position);
m_file.seekg(sizeof(std::uint32_t), std::ios_base::cur);
m_file.seek(it->position);
m_file.seek(sizeof(quint32) + m_file.pos());
// get all MATL subchunk
std::list<ChunkHeader*> tmp_matlChunks;
loadChunks(tmp_matlChunks, m_file.tellg(), it->size - 4);
QList<ChunkHeader*> tmp_matlChunks;
loadChunks(tmp_matlChunks, m_file.pos(), it->size - 4);
// evaluate MATL subchunks
for (auto& it : tmp_matlChunks)
{
// This shouldn't be anything else than MATD
if (!strcmp("MATD", it->name))
if ("MATD" == it->name)
{
// get all subchunks from MATD
std::list<ChunkHeader*> tmp_matdChunks;
QList<ChunkHeader*> tmp_matdChunks;
loadChunks(tmp_matdChunks, it->position, it->size);
m_textureNames->push_back("");
m_materials->push_back(Material());
// analyse MATD subchunks
analyseMatdChunks(tmp_matdChunks);
@ -185,14 +192,15 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
}
// model
else if (!strcmp("MODL", it->name))
else if ("MODL" == it->name)
{
OutputDevice::getInstance()->print("loading model..", 0);
Model* new_model = new Model;
m_currentType = ModelTyp::null;
m_currentRenderFlag = -1;
// get all MODL subchunks
std::list<ChunkHeader*> tmp_chunks;
QList<ChunkHeader*> tmp_chunks;
loadChunks(tmp_chunks, it->position, it->size);
// evaluate MODL subchunks
@ -212,39 +220,146 @@ void MshFile::analyseMsh2Chunks(std::list<ChunkHeader*>& chunkList)
}
}
void MshFile::analyseMatdChunks(std::list<ChunkHeader*>& chunkList)
void MshFile::analyseMatdChunks(QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
if (!strcmp("TX0D", it->name))
// name
if ("NAME" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
m_textureNames->back() = buffer;
m_materials->back().name = buffer;
delete[] buffer;
}
// data
else if("DATA" == it->name)
{
m_file.seek(it->position);
// diffuse
for (unsigned int i = 0; i < 4; i++)
m_file.read(F2V(m_materials->back().diffuseColor[i]), sizeof(float));
// specular
for (unsigned int i = 0; i < 4; i++)
m_file.read(F2V(m_materials->back().specularColor[i]), sizeof(float));
// ambient
for (unsigned int i = 0; i < 4; i++)
m_file.read(F2V(m_materials->back().ambientColor[i]), sizeof(float));
// shininess
m_file.read(F2V(m_materials->back().shininess), sizeof(float));
}
// attributes
else if ("ATRB" == it->name)
{
// get pointer to current material
Material* curMat = &m_materials->back();
// read the attributes
m_file.seek(it->position);
quint8 flag;
m_file.read(F2V(flag), sizeof(flag));
m_file.read(F2V(curMat->rendertype), sizeof(quint8));
m_file.read(F2V(curMat->dataValues[0]), sizeof(quint8));
m_file.read(F2V(curMat->dataValues[1]), sizeof(quint8));
// flags
// 0: emissive
// 1: glow
// 2: single-sided transparency
// 3: double-sided transparency
// 4: hard-edged transparency
// 5: per-pixel lighting
// 6: additive transparency
// 7: specular
for (unsigned int i = 0; i < 8; i++)
curMat->flags[i] = (quint8)(flag << (7 - i)) >> 7;
curMat->transparent = curMat->flags[2] || curMat->flags[3] || curMat->flags[4] || curMat->flags[6] || curMat->rendertype == 4;
}
// texture 0
else if ("TX0D" == it->name)
{
// get the texture name
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
m_materials->back().tx0d = buffer;
delete[] buffer;
// load the texture if the name is not empty
if (!m_materials->back().tx0d.isEmpty())
loadTexture(m_materials->back().texture0, m_filepath, m_materials->back().tx0d);
}
// texture 1
else if ("TX1D" == it->name)
{
// get the texture name
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
m_materials->back().tx1d = buffer;
delete[] buffer;
if (!m_materials->back().tx1d.isEmpty())
loadTexture(m_materials->back().texture1, m_filepath, m_materials->back().tx1d);
}
// texture 2
else if ("TX2D" == it->name)
{
// get the texture name
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
m_materials->back().tx2d = buffer;
delete[] buffer;
}
// texture 3
else if ("TX3D" == it->name)
{
// get the texture name
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
m_materials->back().tx3d = buffer;
delete[] buffer;
}
}
}
void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseModlChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// model type
if (!strcmp("MTYP", it->name))
if ("MTYP" == it->name)
{
m_file.seekg(it->position);
std::uint32_t tmp_type;
m_file.seek(it->position);
quint32 tmp_type;
m_file.read(F2V(tmp_type), sizeof(tmp_type));
m_currentType = (ModelTyp)tmp_type;
}
// parent name
else if (!strcmp("PRNT", it->name))
else if ("PRNT" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -253,9 +368,9 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// model name
else if (!strcmp("NAME", it->name))
else if ("NAME" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
@ -264,20 +379,20 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// render flags
else if (!strcmp("FLGS", it->name))
else if ("FLGS" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
m_file.read(F2V(m_currentRenderFlag), sizeof(m_currentRenderFlag));
}
// translation
else if (!strcmp("TRAN", it->name))
else if ("TRAN" == it->name)
{
float tmp_scale[3];
float tmp_rotation[4];
float tmp_trans[3];
m_file.seekg(it->position);
m_file.seek(it->position);
// read in the data
for (int i = 0; i < 3; i++)
@ -300,10 +415,14 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// geometry data
else if (!strcmp("GEOM", it->name))
else if ("GEOM" == it->name)
{
// don't get null, bone, shadowMesh and hidden mesh indices
if (m_currentType == null || m_currentType == bone || m_currentType == shadowMesh || m_currentRenderFlag == 1)
continue;
// get all GEOM subchunks
std::list<ChunkHeader*> tmp_geomChunks;
QList<ChunkHeader*> tmp_geomChunks;
loadChunks(tmp_geomChunks, it->position, it->size);
// evaluate GEOM subchunks
@ -320,15 +439,15 @@ void MshFile::analyseModlChunks(Model * dataDestination, std::list<ChunkHeader*>
}
}
void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseGeomChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
for (auto& it : chunkList)
{
// segment
if (!strcmp("SEGM", it->name))
if ("SEGM" == it->name)
{
// get all SEGM subchunks
std::list<ChunkHeader*> tmp_segmChunks;
QList<ChunkHeader*> tmp_segmChunks;
loadChunks(tmp_segmChunks, it->position, it->size);
// evaluate SEGM subchunks
@ -344,10 +463,10 @@ void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>
}
// cloth
else if (!strcmp("CLTH", it->name))
else if ("CLTH" == it->name)
{
// get all CLTH subchunks
std::list<ChunkHeader*> tmp_clthChunks;
QList<ChunkHeader*> tmp_clthChunks;
loadChunks(tmp_clthChunks, it->position, it->size);
// evaluate CLTH subchunks
@ -364,52 +483,65 @@ void MshFile::analyseGeomChunks(Model * dataDestination, std::list<ChunkHeader*>
}
}
void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseSegmChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
Segment* new_segment = new Segment;
for (auto& it : chunkList)
{
// material index
if (!strcmp("MATI", it->name))
if ("MATI" == it->name)
{
m_file.seekg(it->position);
m_file.seek(it->position);
m_file.read(F2V(new_segment->textureIndex), sizeof(new_segment->textureIndex));
}
// position list (vertex)
else if (!strcmp("POSL", it->name))
else if ("POSL" == it->name)
{
readVertex(new_segment, it->position);
}
// normals
/*else if (!strcmp("NRML", it->name))
else if ("NRML" == it->name)
{
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
}*/
quint32 tmp_size;
m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
if (tmp_size < (unsigned) new_segment->vertices.size())
{
OutputDevice::getInstance()->print("WARNING: too less normals " + QString::number(tmp_size) + " < " + QString::number(new_segment->vertices.size()), 1);
for (unsigned int i = new_segment->vertices.size(); i != tmp_size; i--)
for (unsigned int j = 0; j < 3; j++)
new_segment->vertices[i - 1].vertexNormal[j] = 0;
}
else if (tmp_size > (unsigned) new_segment->vertices.size())
{
OutputDevice::getInstance()->print("WARNING: too many normals " + QString::number(tmp_size) + " > " + QString::number(new_segment->vertices.size()), 1);
tmp_size = new_segment->vertices.size();
}
for (unsigned int i = 0; i < tmp_size; i++)
for (unsigned int j = 0; j < 3; j++)
m_file.read(F2V(new_segment->vertices[i].vertexNormal[j]), sizeof(float));
}
// uv
else if (!strcmp("UV0L", it->name))
else if ("UV0L" == it->name)
{
readUV(new_segment, it->position);
}
// polygons (indices into vertex/uv list)
else if (!strcmp("STRP", it->name))
else if ("STRP" == it->name)
{
// don't get null, bone, shadowMesh and hidden mesh indices
if (m_currentType == null || m_currentType == bone || m_currentType == shadowMesh || m_currentRenderFlag == 1)
continue;
// jump to the data section and read the size;
std::uint32_t tmp_size;
m_file.seekg(it->position);
quint32 tmp_size;
m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
int highBitCount(0);
@ -418,7 +550,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
for (unsigned int i = 0; i < tmp_size; i++)
{
// ReadData
std::uint16_t tmp_value;
quint16 tmp_value;
m_file.read(F2V(tmp_value), sizeof(tmp_value));
// Check if highbit is set
@ -426,7 +558,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
{
highBitCount++;
// remove the high bit, to get the actually value
tmp_value = (std::uint16_t(tmp_value << 1) >> 1);
tmp_value = (quint16(tmp_value << 1) >> 1);
}
// save data
@ -440,18 +572,106 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
if (tmp_buffer.size() == 5)
{
for (size_t i = 0; i < 3; i++)
new_segment->indices.push_back(tmp_buffer.takeFirst());
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
for (int k = 0; k < 3; k++)
{
// polygon normal wasn't calculated before
if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
new_segment->vertices[tmp_buffer[k]].tangent = tan;
new_segment->vertices[tmp_buffer[k]].bitangent = bi;
new_segment->indices.push_back(tmp_buffer[k]);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
tmp_buffer.remove(0, 3);
}
else if (tmp_buffer.size() > 5)
{
unsigned int tmp_multiPolySize = tmp_buffer.size() - 2;
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
// for every triangle of the multi polygon..
for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
{
// ..calculate the edge indices
for (int triEdge = 0; triEdge < 3; triEdge++)
new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
{
int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];
// polygon normal wasn't calculated before
if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[curIndi].polygonNormal = norm;
new_segment->vertices[curIndi].tangent = tan;
new_segment->vertices[curIndi].bitangent = bi;
new_segment->indices.push_back(curIndi);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[curIndi]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
}
tmp_buffer.remove(0, tmp_multiPolySize);
}
@ -462,17 +682,106 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
// save the last polygon (no 2 high bit followed)
if (tmp_buffer.size() == 3)
{
for (size_t i = 0; i < 3; i++)
new_segment->indices.push_back(tmp_buffer.takeFirst());
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
for (int k = 0; k < 3; k++)
{
// polygon normal wasn't calculated before
if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
new_segment->vertices[tmp_buffer[k]].tangent = tan;
new_segment->vertices[tmp_buffer[k]].bitangent = bi;
new_segment->indices.push_back(tmp_buffer[k]);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
tmp_buffer.remove(0, 3);
}
else if (tmp_buffer.size() > 3)
{
unsigned int tmp_multiPolySize = tmp_buffer.size();
// calculate poylgon normal, tangent and bitangent
QVector3D vec1, vec2, norm, tan, bi;
QVector2D uv1, uv2;
float f;
vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
norm = QVector3D::crossProduct(vec1, vec2).normalized();
tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
tan.normalize();
bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
bi.normalize();
// for every triangle of the multi polygon..
for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
{
// ..calculate the edge indices
for (int triEdge = 0; triEdge < 3; triEdge++)
new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
{
int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];
// polygon normal wasn't calculated before
if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
{
new_segment->vertices[curIndi].polygonNormal = norm;
new_segment->vertices[curIndi].tangent = tan;
new_segment->vertices[curIndi].bitangent = bi;
new_segment->indices.push_back(curIndi);
}
// polygon normal already calculated so duplicate the vertex
else
{
new_segment->vertices.push_back(new_segment->vertices[curIndi]);
new_segment->vertices.back().polygonNormal = norm;
new_segment->vertices.back().tangent = tan;
new_segment->vertices.back().bitangent = bi;
new_segment->indices.push_back(new_segment->vertices.size() - 1);
}
}
}
}
}
}
@ -480,63 +789,77 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
dataDestination->segmList.push_back(new_segment);
}
void MshFile::analyseClthChunks(Model * dataDestination, std::list<ChunkHeader*>& chunkList)
void MshFile::analyseClthChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
{
Segment* new_segment = new Segment;
for (auto& it : chunkList)
{
// texture name
if (!strcmp("CTEX", it->name))
if ("CTEX" == it->name)
{
// read the texture name
m_file.seekg(it->position);
m_file.seek(it->position);
char* buffer = new char[it->size + 1];
*buffer = { 0 };
m_file.read(buffer, it->size);
// search if it is already known
bool tmp_found(false);
m_materials->push_back(Material());
m_materials->back().name = "Cloth Material";
m_materials->back().tx0d = QString(buffer);
int index = m_textureNames->indexOf(QString::fromStdString(buffer));
if (index != -1)
new_segment->textureIndex = index;
else
{
m_textureNames->push_back(QString::fromStdString(buffer));
new_segment->textureIndex = m_textureNames->size() - 1;
}
m_materials->back().shininess = 10;
if (!m_materials->back().tx0d.isEmpty())
loadTexture(m_materials->back().texture0, m_filepath, m_materials->back().tx0d);
new_segment->textureIndex = m_materials->size() - 1;
delete[] buffer;
}
// position list (vertex)
else if (!strcmp("CPOS", it->name))
else if ("CPOS" == it->name)
{
readVertex(new_segment, it->position);
}
// uv
else if (!strcmp("CUV0", it->name))
else if ("CUV0" == it->name)
{
readUV(new_segment, it->position);
}
// triangles (indices into vertex/uv list)
else if (!strcmp("CMSH", it->name))
else if ("CMSH" == it->name)
{
// jump to the data section and read the size;
std::uint32_t tmp_size;
m_file.seekg(it->position);
quint32 tmp_size;
m_file.seek(it->position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
// for every triangle..
for (unsigned int i = 0; i < tmp_size * 3; i++)
for (unsigned int i = 0; i < tmp_size; i++)
{
std::uint32_t tmp_value;
m_file.read(F2V(tmp_value), sizeof(std::uint32_t));
quint32 tmp_value[3];
for (unsigned int j = 0; j < 3; j++)
{
m_file.read(F2V(tmp_value[j]), sizeof(quint32));
new_segment->indices.push_back((GLuint)tmp_value[j]);
}
new_segment->indices.push_back((GLuint)tmp_value);
QVector3D vec1, vec2, norm;
vec1 = new_segment->vertices[new_segment->indices[i * 3]].position - new_segment->vertices[new_segment->indices[i * 3 + 1]].position;
vec2 = new_segment->vertices[new_segment->indices[i * 3]].position - new_segment->vertices[new_segment->indices[i * 3 + 2]].position;
norm = QVector3D::crossProduct(vec1, vec2);
for (int k = 0; k < 3; k++)
{
new_segment->vertices[new_segment->indices[i * 3 + k]].vertexNormal += norm;
new_segment->vertices[new_segment->indices[i * 3 + k]].vertexNormal.normalize();
}
}
}
}
@ -544,10 +867,10 @@ void MshFile::analyseClthChunks(Model * dataDestination, std::list<ChunkHeader*>
dataDestination->segmList.push_back(new_segment);
}
void MshFile::readVertex(Segment * dataDestination, std::streampos position)
void MshFile::readVertex(Segment * dataDestination, qint64 position)
{
std::uint32_t tmp_size;
m_file.seekg(position);
quint32 tmp_size;
m_file.seek(position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
for (unsigned int i = 0; i < tmp_size; i++)
@ -563,41 +886,69 @@ void MshFile::readVertex(Segment * dataDestination, std::streampos position)
}
}
void MshFile::readUV(Segment * dataDestination, std::streampos position)
void MshFile::readUV(Segment * dataDestination, qint64 position)
{
std::uint32_t tmp_size;
m_file.seekg(position);
quint32 tmp_size;
m_file.seek(position);
m_file.read(F2V(tmp_size), sizeof(tmp_size));
if (tmp_size < dataDestination->vertices.size())
if (tmp_size < (unsigned) dataDestination->vertices.size())
{
emit sendMessage("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
OutputDevice::getInstance()->print("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
for (unsigned int i = dataDestination->vertices.size(); i != tmp_size; i--)
for (unsigned int j = 0; j < 2; j++)
dataDestination->vertices[i - 1].texCoord[j] = 0;
}
else if (tmp_size > dataDestination->vertices.size())
else if (tmp_size > (unsigned) dataDestination->vertices.size())
{
emit sendMessage("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
OutputDevice::getInstance()->print("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
tmp_size = dataDestination->vertices.size();
}
for (unsigned int i = 0; i < tmp_size; i++)
{
float tmp[2];
for (unsigned int j = 0; j < 2; j++)
m_file.read(F2V(dataDestination->vertices[i].texCoord[j]), sizeof(float));
}
}
QMatrix4x4 MshFile::getParentMatrix(std::string parent) const
void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
{
bool loadSuccess(false);
QImage img = loadTga(filepath + "/" + filename, loadSuccess);
if (!loadSuccess)
{
OutputDevice::getInstance()->print("WARNING: texture not found or corrupted: " + filename, 1);
//TODO: cloth use the wrong diffuse color. should be null
img = QImage(1, 1, QImage::Format_RGB32);
img.fill(QColor(m_materials->back().diffuseColor[0] * 255, m_materials->back().diffuseColor[1] * 255, m_materials->back().diffuseColor[2] * 255));
filename += " *";
}
// Load image to OglTexture
QOpenGLTexture* new_texture = new QOpenGLTexture(img.mirrored());
// Set nearest filtering mode for texture minification
new_texture->setMinificationFilter(QOpenGLTexture::Nearest);
// Set bilinear filtering mode for texture magnification
new_texture->setMagnificationFilter(QOpenGLTexture::Linear);
// Wrap texture coordinates by repeating
// f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
new_texture->setWrapMode(QOpenGLTexture::Repeat);
destination = new_texture;
}
QMatrix4x4 MshFile::getParentMatrix(QString parent) const
{
QMatrix4x4 matrix;
for (auto& it : *m_models)
{
if (!strcmp(parent.c_str(), it->name.c_str()))
if (parent == it->name)
{
matrix = getParentMatrix(it->parent) * it->m4x4Translation;
break;
@ -607,13 +958,13 @@ QMatrix4x4 MshFile::getParentMatrix(std::string parent) const
return matrix;
}
QQuaternion MshFile::getParentRotation(std::string parent) const
QQuaternion MshFile::getParentRotation(QString parent) const
{
QQuaternion rotation;
for (auto& it : *m_models)
{
if (!strcmp(parent.c_str(), it->name.c_str()))
if (parent == it->name)
{
rotation = getParentRotation(it->parent) * it->quadRotation;
break;

View File

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

View File

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

View File

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

View File

@ -0,0 +1,183 @@
#include "..\Header\SettingsWindow.h"
#include "..\Header\SettingsManager.h"
/////////////////////////////////////////////////////////////////////////
// constructor/destructor
SettingsWindow::SettingsWindow(QWidget * parent)
: QWidget(parent)
, ui(new Ui::SettingsWindow)
{
ui->setupUi(this);
setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
setupConnections();
// set default values
SettingsManager* sm = SettingsManager::getInstance(this);
ui->lightOff_R_SB->setValue((int)(sm->getBgColorOff()[0]));
ui->lightOff_G_SB->setValue((int)(sm->getBgColorOff()[1]));
ui->lightOff_B_SB->setValue((int)(sm->getBgColorOff()[2]));
ui->lightOn_R_SB->setValue((int)(sm->getBgColorOn()[0]));
ui->lightOn_G_SB->setValue((int)(sm->getBgColorOn()[1]));
ui->lightOn_B_SB->setValue((int)(sm->getBgColorOn()[2]));
ui->light_R_SB->setValue((int)(sm->getLightColor()[0]));
ui->light_G_SB->setValue((int)(sm->getLightColor()[1]));
ui->light_B_SB->setValue((int)(sm->getLightColor()[2]));
ui->ambCoef->setValue(sm->getAmbient());
ui->attFac->setValue(sm->getAttenuation());
ui->checkBackfaceCulling->setChecked(sm->isBfCulling());
ui->checkAutoColor->setChecked(sm->isAutoColor());
ui->checkHeadlight->setChecked(sm->isHeadlight());
if (sm->getLightType() == 1)
ui->radioDirectLight->setChecked(true);
else
ui->radioPointLight->setChecked(true);
connect(this, &SettingsWindow::updateBGColorOff, sm, &SettingsManager::setBgColorOff);
connect(this, &SettingsWindow::updateBGColorOn, sm, &SettingsManager::setBgColorOn);
connect(this, &SettingsWindow::updateLightColor, sm, &SettingsManager::setLightColor);
connect(this, &SettingsWindow::updateAttFac, sm, &SettingsManager::setAttenuation);
connect(this, &SettingsWindow::updateAmbCoef, sm, &SettingsManager::setAmbient);
connect(this, &SettingsWindow::sendHeadlight, sm, &SettingsManager::setHeadlight);
connect(this, &SettingsWindow::sendBackfaceCulling, sm, &SettingsManager::setBfCulling);
connect(ui->checkAutoColor, &QCheckBox::stateChanged, sm, &SettingsManager::setAutoColor);
connect(this, &SettingsWindow::changeLightType, sm, &SettingsManager::setLightType);
}
SettingsWindow::~SettingsWindow()
{
delete ui;
}
/////////////////////////////////////////////////////////////////////////
// functions
void SettingsWindow::setupConnections()
{
// light off
connect(ui->lightOff_R_SB, SIGNAL(valueChanged(int)), ui->lightOff_R_S, SLOT(setValue(int)));
connect(ui->lightOff_R_S, SIGNAL(valueChanged(int)), ui->lightOff_R_SB, SLOT(setValue(int)));
connect(ui->lightOff_R_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
connect(ui->lightOff_G_SB, SIGNAL(valueChanged(int)), ui->lightOff_G_S, SLOT(setValue(int)));
connect(ui->lightOff_G_S, SIGNAL(valueChanged(int)), ui->lightOff_G_SB, SLOT(setValue(int)));
connect(ui->lightOff_G_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
connect(ui->lightOff_B_SB, SIGNAL(valueChanged(int)), ui->lightOff_B_S, SLOT(setValue(int)));
connect(ui->lightOff_B_S, SIGNAL(valueChanged(int)), ui->lightOff_B_SB, SLOT(setValue(int)));
connect(ui->lightOff_B_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOffChanged);
// light on
connect(ui->lightOn_R_SB, SIGNAL(valueChanged(int)), ui->lightOn_R_S, SLOT(setValue(int)));
connect(ui->lightOn_R_S, SIGNAL(valueChanged(int)), ui->lightOn_R_SB, SLOT(setValue(int)));
connect(ui->lightOn_R_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
connect(ui->lightOn_G_SB, SIGNAL(valueChanged(int)), ui->lightOn_G_S, SLOT(setValue(int)));
connect(ui->lightOn_G_S, SIGNAL(valueChanged(int)), ui->lightOn_G_SB, SLOT(setValue(int)));
connect(ui->lightOn_G_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
connect(ui->lightOn_B_SB, SIGNAL(valueChanged(int)), ui->lightOn_B_S, SLOT(setValue(int)));
connect(ui->lightOn_B_S, SIGNAL(valueChanged(int)), ui->lightOn_B_SB, SLOT(setValue(int)));
connect(ui->lightOn_B_S, &QSlider::valueChanged, this, &SettingsWindow::backgroundColorOnChanged);
// light
connect(ui->light_R_SB, SIGNAL(valueChanged(int)), ui->light_R_S, SLOT(setValue(int)));
connect(ui->light_R_S, SIGNAL(valueChanged(int)), ui->light_R_SB, SLOT(setValue(int)));
connect(ui->light_R_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged);
connect(ui->light_G_SB, SIGNAL(valueChanged(int)), ui->light_G_S, SLOT(setValue(int)));
connect(ui->light_G_S, SIGNAL(valueChanged(int)), ui->light_G_SB, SLOT(setValue(int)));
connect(ui->light_G_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged);
connect(ui->light_B_SB, SIGNAL(valueChanged(int)), ui->light_B_S, SLOT(setValue(int)));
connect(ui->light_B_S, SIGNAL(valueChanged(int)), ui->light_B_SB, SLOT(setValue(int)));
connect(ui->light_B_S, &QSlider::valueChanged, this, &SettingsWindow::lightColorChanged);
connect(ui->checkAutoColor, &QCheckBox::toggled, this, &SettingsWindow::autoColorToggled);
connect(ui->radioDirectLight, &QRadioButton::toggled, this, &SettingsWindow::radioToggled);
connect(ui->ambCoef, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAmbCoef(value); });
connect(ui->attFac, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) {emit updateAttFac(value); });
connect(ui->checkBackfaceCulling, &QCheckBox::toggled, [this]() {emit sendBackfaceCulling(ui->checkBackfaceCulling->isChecked()); });
connect(ui->spinZSpeed, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int value) {emit sendZommSpeed(value); });
connect(ui->checkHeadlight, &QCheckBox::toggled, [this]() {emit sendHeadlight(ui->checkHeadlight->isChecked()); });
}
/////////////////////////////////////////////////////////////////////////
// slots
void SettingsWindow::autoColorToggled()
{
if (!ui->checkAutoColor->isChecked())
{
ui->lightOn_R_SB->setEnabled(true);
ui->lightOn_R_S->setEnabled(true);
ui->lightOn_G_SB->setEnabled(true);
ui->lightOn_G_S->setEnabled(true);
ui->lightOn_B_SB->setEnabled(true);
ui->lightOn_B_S->setEnabled(true);
}
else
{
ui->lightOn_R_SB->setEnabled(false);
ui->lightOn_R_S->setEnabled(false);
ui->lightOn_G_SB->setEnabled(false);
ui->lightOn_G_S->setEnabled(false);
ui->lightOn_B_SB->setEnabled(false);
ui->lightOn_B_S->setEnabled(false);
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::radioToggled()
{
if (ui->radioDirectLight->isChecked())
{
ui->attFac->setValue(0.0);
ui->attFac->setEnabled(false);
emit changeLightType(1);
}
else
{
ui->attFac->setEnabled(true);
emit changeLightType(2);
}
}
void SettingsWindow::backgroundColorOffChanged()
{
emit updateBGColorOff(QVector3D(ui->lightOff_R_S->value(), ui->lightOff_G_S->value(), ui->lightOff_B_S->value()));
}
void SettingsWindow::backgroundColorOnChanged()
{
emit updateBGColorOn(QVector3D(ui->lightOn_R_S->value(), ui->lightOn_G_S->value(), ui->lightOn_B_S->value()));
}
void SettingsWindow::lightColorChanged()
{
emit updateLightColor(QVector3D(ui->light_R_S->value(), ui->light_G_S->value(), ui->light_B_S->value()));
if (ui->checkAutoColor->isChecked())
{
ui->lightOn_R_S->setValue((int)(ui->light_R_S->value() / 50));
ui->lightOn_G_S->setValue((int)(ui->light_G_S->value() / 50));
ui->lightOn_B_S->setValue((int)(ui->light_B_S->value() / 50));
}
}

View File

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

View File

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

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: 48 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;
}

Some files were not shown because too many files have changed in this diff Show More