Browse Source

Initial commit

texture
Shaun Reed 1 year ago
parent
commit
578fcb2bbd
  1. 6
      .gitignore
  2. 152
      CMakeLists.txt
  3. 60
      README.md
  4. 38
      app/main.cpp
  5. 58
      lib/camera3d.cpp
  6. 62
      lib/camera3d.h
  7. 185
      lib/input.cpp
  8. 63
      lib/input.h
  9. 1064
      lib/mainwidget.cpp
  10. 84
      lib/mainwidget.h
  11. 336
      lib/mesh.cpp
  12. 131
      lib/mesh.h
  13. 171
      lib/meshrenderer.cpp
  14. 76
      lib/meshrenderer.h
  15. 401
      lib/model.cpp
  16. 139
      lib/model.h
  17. 9
      lib/object.cpp
  18. 62
      lib/object.h
  19. 100
      lib/skybox.cpp
  20. 48
      lib/skybox.h
  21. 103
      lib/texture.cpp
  22. 44
      lib/texture.h
  23. 144
      lib/transform3D.cpp
  24. 117
      lib/transform3D.h
  25. 4
      qtk_en_US.ts
  26. 81
      resources.qrc
  27. BIN
      resources/images/crate.png
  28. BIN
      resources/images/stone.png
  29. BIN
      resources/images/wood.png
  30. 55
      resources/models/alien-hominid/alien.mtl
  31. 116822
      resources/models/alien-hominid/alien.obj
  32. BIN
      resources/models/alien-hominid/blaster_diffuse.png
  33. BIN
      resources/models/alien-hominid/blaster_emissive.png
  34. BIN
      resources/models/alien-hominid/blaster_normal.png
  35. BIN
      resources/models/alien-hominid/blaster_roughness.png
  36. BIN
      resources/models/alien-hominid/blaster_specular.png
  37. BIN
      resources/models/alien-hominid/diffuse.png
  38. BIN
      resources/models/alien-hominid/normal.png
  39. BIN
      resources/models/alien-hominid/roughness.png
  40. BIN
      resources/models/alien-hominid/specular.png
  41. BIN
      resources/models/backpack/ao.jpg
  42. 16
      resources/models/backpack/backpack.mtl
  43. 199481
      resources/models/backpack/backpack.obj
  44. BIN
      resources/models/backpack/diffuse.jpg
  45. BIN
      resources/models/backpack/normal.png
  46. BIN
      resources/models/backpack/roughness.jpg
  47. 3
      resources/models/backpack/source_attribution.txt
  48. BIN
      resources/models/backpack/specular.jpg
  49. 7
      resources/models/bird/bird.mtl
  50. 80009
      resources/models/bird/bird.obj
  51. BIN
      resources/models/bird/diffuse.jpg
  52. BIN
      resources/models/bird/normal.jpg
  53. BIN
      resources/models/bird/occlusion.jpg
  54. 12
      resources/models/floor.obj
  55. BIN
      resources/models/lion/diffuse.jpg
  56. BIN
      resources/models/lion/height.jpg
  57. 16
      resources/models/lion/lion.mtl
  58. 86063
      resources/models/lion/lion.obj
  59. BIN
      resources/models/lion/normal.jpg
  60. BIN
      resources/models/lion/roughness.jpg
  61. BIN
      resources/models/lion/specular.jpg
  62. BIN
      resources/models/scythe/diffuse.png
  63. 8
      resources/models/scythe/scythe.mtl
  64. 5915
      resources/models/scythe/scythe.obj
  65. BIN
      resources/models/spartan/Spartan_Arms_Mat_AO.png
  66. BIN
      resources/models/spartan/Spartan_Arms_Mat_BaseColor.png
  67. BIN
      resources/models/spartan/Spartan_Arms_Mat_Metallic.png
  68. BIN
      resources/models/spartan/Spartan_Arms_Mat_Normal.png
  69. BIN
      resources/models/spartan/Spartan_Arms_Mat_Roughness.png
  70. BIN
      resources/models/spartan/Spartan_Arms_Mat_Specular.png
  71. BIN
      resources/models/spartan/Spartan_Chest_Mat_AO.png
  72. BIN
      resources/models/spartan/Spartan_Chest_Mat_BaseColor.png
  73. BIN
      resources/models/spartan/Spartan_Chest_Mat_Metallic.png
  74. BIN
      resources/models/spartan/Spartan_Chest_Mat_Normal.png
  75. BIN
      resources/models/spartan/Spartan_Chest_Mat_Roughness.png
  76. BIN
      resources/models/spartan/Spartan_Chest_Mat_Specular.png
  77. BIN
      resources/models/spartan/Spartan_Ears_Mat_AO.png
  78. BIN
      resources/models/spartan/Spartan_Ears_Mat_BaseColor.png
  79. BIN
      resources/models/spartan/Spartan_Ears_Mat_Metallic.png
  80. BIN
      resources/models/spartan/Spartan_Ears_Mat_Normal.png
  81. BIN
      resources/models/spartan/Spartan_Ears_Mat_Roughness.png
  82. BIN
      resources/models/spartan/Spartan_Ears_Mat_Specular.png
  83. BIN
      resources/models/spartan/Spartan_Helmet_Mat_AO.png
  84. BIN
      resources/models/spartan/Spartan_Helmet_Mat_BaseColor.png
  85. BIN
      resources/models/spartan/Spartan_Helmet_Mat_Metallic.png
  86. BIN
      resources/models/spartan/Spartan_Helmet_Mat_Normal.png
  87. BIN
      resources/models/spartan/Spartan_Helmet_Mat_Roughness.png
  88. BIN
      resources/models/spartan/Spartan_Helmet_Mat_Specular.png
  89. BIN
      resources/models/spartan/Spartan_Legs_Mat_AO.png
  90. BIN
      resources/models/spartan/Spartan_Legs_Mat_BaseColor.png
  91. BIN
      resources/models/spartan/Spartan_Legs_Mat_Metallic.png
  92. BIN
      resources/models/spartan/Spartan_Legs_Mat_Normal.png
  93. BIN
      resources/models/spartan/Spartan_Legs_Mat_Roughness.png
  94. BIN
      resources/models/spartan/Spartan_Legs_Mat_Specular.png
  95. BIN
      resources/models/spartan/Spartan_Shoulder_Mat_AO.png
  96. BIN
      resources/models/spartan/Spartan_Shoulder_Mat_BaseColor.png
  97. BIN
      resources/models/spartan/Spartan_Shoulder_Mat_Metallic.png
  98. BIN
      resources/models/spartan/Spartan_Shoulder_Mat_Normal.png
  99. BIN
      resources/models/spartan/Spartan_Shoulder_Mat_Roughness.png
  100. BIN
      resources/models/spartan/Spartan_Shoulder_Mat_Specular.png
  101. Some files were not shown because too many files have changed in this diff Show More

6
.gitignore vendored

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
# CLion
**/.idea/**
# CMake build files
**/cmake-build-debug/**
# C++ objects and libs
*.slo
*.lo

152
CMakeLists.txt

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
################################################################################
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
## ##
## Project for working with OpenGL and Qt5 widgets ##
################################################################################
cmake_minimum_required(VERSION 3.5)
project(
#[[NAME]] Qtk
VERSION 1.0
DESCRIPTION "An example project using QT and OpenGL"
LANGUAGES CXX
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find all Qt package components required for this project
find_package(Qt5 COMPONENTS Core LinguistTools Gui Widgets REQUIRED)
# Add our Qt resources.qrc file to our application
set(SOURCES app/main.cpp)
qt5_add_resources(SOURCES resources.qrc)
# Set translation files
set(TS_FILES qtk_en_US.ts)
add_executable(
qtk # Executable name
${SOURCES} # Executable source code
${TS_FILES} # Link translation files
)
################################################################################
# External Libraries
################################################################################
# Find and link GLUT package; Otherwise show an error
find_package(GLUT REQUIRED)
if (!GLUT_FOUND)
message(
"Error: CMake was unable to find the GLUT package\n"
"Please install GLUT (freeglut3-dev) and try again\n"
"sudo apt install freeglut3-dev\n"
)
endif()
# Find and link OpenGL package; Otherwise show an error
set(OpenGL_GL_PREFERENCE LEGACY)
find_package(OpenGL REQUIRED)
if (!OPENGL_FOUND)
message(
"Error: CMake was unable to find the OpenGL package\n"
"Please install OpenGL and try again\n"
"sudo apt install mesa-utils\n"
)
endif()
# https://github.com/assimp/assimp/commit/6ac8279977c3a54118551e549d77329497116f66
find_package(assimp REQUIRED)
if (!assimp_FOUND)
message(
"Error: CMake was unable to find the Assimp package\n"
"Please install Assimp and try again\n"
"sudo apt install libassimp-dev\n"
)
endif()
################################################################################
# Custom Libraries
################################################################################
# Mainwidget
add_library(main-widget lib/mainwidget.cpp)
target_include_directories(main-widget PUBLIC lib/)
#target_link_libraries(main-widget PUBLIC Qt5::Widgets)
# + This lib and all linked targets will also link to OpenGL
target_include_directories(main-widget PUBLIC ${OPENGL_INCLUDE_DIR})
target_link_libraries(main-widget PUBLIC ${OPENGL_LIBRARIES})
# Model
add_library(model lib/model.cpp)
target_include_directories(model PRIVATE ${ASSIMP_INCLUDE_DIR})
target_link_libraries(model PRIVATE ${ASSIMP_LIBRARIES})
target_link_libraries(model PUBLIC Qt5::Widgets)
target_link_libraries(model PRIVATE main-widget)
# Input
add_library(input lib/input.cpp)
target_include_directories(input PUBLIC lib/)
target_link_libraries(input PUBLIC Qt5::Widgets)
# Mesh
add_library(mesh lib/mesh.cpp)
target_include_directories(mesh PUBLIC lib/)
target_link_libraries(mesh PUBLIC Qt5::Widgets)
# Transform3D
add_library(transform3d lib/transform3D.cpp)
target_include_directories(transform3d PUBLIC lib/)
target_link_libraries(transform3d PUBLIC Qt5::Widgets)
# Camera3D
add_library(camera3d lib/camera3d.cpp)
target_include_directories(camera3d PUBLIC lib/)
target_link_libraries(camera3d PUBLIC Qt5::Widgets)
# Texture
add_library(texture lib/texture.cpp)
target_include_directories(texture PUBLIC lib/)
target_link_libraries(texture PUBLIC Qt5::Widgets)
# Object
add_library(object lib/object.cpp)
target_include_directories(object PUBLIC lib/)
target_link_libraries(object PUBLIC Qt5::Widgets)
# MeshRenderer
add_library(meshrenderer lib/meshrenderer.cpp)
target_include_directories(meshrenderer PUBLIC lib/)
target_link_libraries(meshrenderer PUBLIC Qt5::Widgets)
# Skybox
add_library(skybox lib/skybox.cpp)
target_link_libraries(skybox PUBLIC Qt5::Widgets)
target_link_libraries(skybox PRIVATE mesh)
target_link_libraries(skybox PRIVATE camera3d)
################################################################################
# Final Application
################################################################################
target_link_libraries(main-widget PUBLIC model)
target_link_libraries(main-widget PUBLIC input)
target_link_libraries(main-widget PUBLIC transform3d)
target_link_libraries(main-widget PUBLIC object)
target_link_libraries(main-widget PUBLIC meshrenderer)
target_link_libraries(main-widget PUBLIC texture)
target_link_libraries(main-widget PUBLIC skybox)
target_link_libraries(main-widget PUBLIC mesh)
# Link qtk executable to main main-widget library
target_link_libraries(qtk PUBLIC main-widget)
# Set up QT Linguist translation
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})

60
README.md

@ -1,2 +1,58 @@ @@ -1,2 +1,58 @@
# qtk
Practice using OpenGL in Qt5 widget application
# Qtk
Practice project for learning about using OpenGL in Qt5 widget applications.
Model loader using [Assimp](https://assimp.org/).
You can fly around and see the examples I made, or import your own models within
`mainwdget.cpp`, inside the `MainWidget::initObjects()` function. I've commented
throughout the code there to explain which model or example I'm modifying.
Rotations and translations happen in `MainWidget::update()`, to get textures
loading on models look into
[material files](http://www.paulbourke.net/dataformats/mtl/) and see some
examples in the `resources/models/` directory.
Can be built with cmake manually or using
[Qt Creator](https://github.com/qt-creator/qt-creator).
To build and run `qtk` on Ubuntu -
```bash
# Qt Creator
sudo apt update -y && sudo apt install qttools5-dev freeglut3-dev libassimp-dev
git clone https://gitlab.com/shaunrd0/qtk
mkdir build && cd build
cmake .. && cmake --build
./qtk
```
You can fly around the scene if you hold the right mouse button and use WASD.
If you see a small triangle floating by a model it represents the light source
that is being used for the shader rendering the model. These appear on models
using phong, specular, and diffuse lighting techniques.
![](resources/screenshot.png)
Spartan with no normals -
![](resources/spartan-specular.png)
Spartan with normals -
![](resources/spartan-normals.png)
## Model Artists
"Alien Hominid" (https://skfb.ly/onStx) by Nwilly_art is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Scythe World Of Warcraft" (https://skfb.ly/6UooG) by Warcraft-3D-Models is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Spartan Armour MKV - Halo Reach" () by McCarthy3D is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Survival Guitar Backpack (Low Poly)" (https://skfb.ly/6RnCB) by Berk Gedik is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36
Modified material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup.
"Terror-bird (NHMW-Geo 2012/0007/0001)" (https://skfb.ly/onAWy) by Natural History Museum Vienna is licensed under Creative Commons Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/).
"Golden Lion Sitting OBJ Low Poly FREE" (https://skfb.ly/onZAH) by LordSamueliSolo is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).

38
app/main.cpp

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Main program for practice using Qt5 widgets and OpenGL ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <QApplication>
#include <QLabel>
#include <mainwidget.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Set OpenGL Version information
// Note: This format must be set before show() is called.
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(4,5);
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
format.setSamples(4);
// Set the size of teh depth bufer for glEnable(GL_DEPTH_TEST)
format.setDepthBufferSize(16);
#ifdef QTK_DEBUG
format.setOption(QSurfaceFormat::DebugContext);
#endif // QTK_DEBUG
// Set the widget up using a custom format
MainWidget widget(format);
return a.exec();
}

58
lib/camera3d.cpp

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Fly camera class from tutorials followed at trentreed.net ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <camera3d.h>
const QVector3D Camera3D::LocalForward(0.0f, 0.0f, -1.0f);
const QVector3D Camera3D::LocalUp(0.0f, 1.0f, 0.0f);
const QVector3D Camera3D::LocalRight(1.0f, 0.0f, 0.0f);
/*******************************************************************************
* Accessors
******************************************************************************/
// Produces worldToView matrix
const QMatrix4x4 & Camera3D::toMatrix()
{
mWorld.setToIdentity();
mWorld.rotate(mTransform.rotation().conjugate());
mWorld.translate(-mTransform.translation());
return mWorld;
}
/*******************************************************************************
* Qt Streams
******************************************************************************/
QDataStream & operator<<(QDataStream & out, Camera3D & transform)
{
out << transform.transform();
return out;
}
QDataStream & operator>>(QDataStream & in, Camera3D & transform)
{
in >> transform.transform();
return in;
}
QDebug operator<<(QDebug dbg, const Camera3D & transform)
{
dbg << "Camera3D\n{\n";
dbg << "Position: <" << transform.translation().x() << ", "
<< transform.translation().y() << ", "
<< transform.translation().z() << ">\n";
dbg << "Rotation: <" << transform.rotation().x() << ", "
<< transform.rotation().y() << ", "
<< transform.rotation().z() << " | "
<< transform.rotation().scalar() << ">\n}";
return dbg;
}

62
lib/camera3d.h

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Fly camera class from tutorials followed at trentreed.net ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_CAMERA3D_H
#define QTK_CAMERA3D_H
#include <QDebug>
#include <transform3D.h>
class Camera3D {
public:
// Constants
static const QVector3D LocalForward;
static const QVector3D LocalUp;
static const QVector3D LocalRight;
// Accessors
inline Transform3D & transform() { return mTransform;}
inline const QVector3D & translation() const
{ return mTransform.translation();}
inline const QQuaternion & rotation() const
{ return mTransform.rotation();}
const QMatrix4x4 & toMatrix();
// Queries
inline QVector3D forward() const
{ return mTransform.rotation().rotatedVector(LocalForward);}
inline QVector3D right() const
{ return mTransform.rotation().rotatedVector(LocalRight);}
inline QVector3D up() const
{ return mTransform.rotation().rotatedVector(LocalUp);}
private:
Transform3D mTransform;
QMatrix4x4 mWorld;
#ifndef QT_NO_DATASTREAM
friend QDataStream & operator<<(QDataStream & out, Camera3D & transform);
friend QDataStream & operator>>(QDataStream & in, Camera3D & transform);
#endif
};
Q_DECLARE_TYPEINFO(Camera3D, Q_MOVABLE_TYPE);
// Qt Streams
#ifndef QT_NO_DATASTREAM
QDataStream & operator<<(QDataStream & out, const Camera3D & transform);
QDataStream & operator>>(QDataStream & in, Camera3D & transform);
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const Camera3D & transform);
#endif
#endif // QTK_CAMERA3D_H

185
lib/input.cpp

@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Input class from tutorials followed at trentreed.net ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <algorithm>
#include <vector>
#include <QCursor>
#include <input.h>
/*******************************************************************************
* Static Helper Structs
******************************************************************************/
template <typename T>
struct InputInstance : std::pair<T, Input::InputState>
{
typedef std::pair<T, Input::InputState> base_class;
inline InputInstance(T value)
: base_class(value, Input::InputInvalid) {}
inline InputInstance(T value, Input::InputState state)
: base_class(value, state) {}
inline bool operator==(const InputInstance & rhs) const
{ return this->first == rhs.first;}
};
// Key, button instance typedefs
typedef InputInstance<Qt::Key> KeyInstance;
typedef InputInstance<Qt::MouseButton> ButtonInstance;
// Key, button instance container typedefs
typedef std::vector<KeyInstance> KeyContainer;
typedef std::vector<ButtonInstance> ButtonContainer;
// Static containers for key, button instances
static KeyContainer sg_keyInstances;
static ButtonContainer sg_buttonInstances;
// Static containers for mouse data
static QPoint sg_mouseCurrPosition;
static QPoint sg_mousePrevPosition;
static QPoint sg_mouseDelta;
/*******************************************************************************
* Static Inline Helper Functions
******************************************************************************/
static inline KeyContainer::iterator FindKey(Qt::Key value)
{
return std::find(sg_keyInstances.begin(), sg_keyInstances.end(), value);
}
static inline ButtonContainer::iterator FindButton(Qt::MouseButton value)
{
return std::find(sg_buttonInstances.begin(), sg_buttonInstances.end(), value);
}
template <typename TPair>
static inline void UpdateStates(TPair & instance)
{
switch (instance.second)
{
case Input::InputRegistered:
instance.second = Input::InputTriggered;
break;
case Input::InputTriggered:
instance.second = Input::InputPressed;
break;
case Input::InputUnregistered:
instance.second = Input::InputReleased;
break;
default:
break;
}
}
template <typename TPair>
static inline bool CheckReleased(const TPair & instance)
{
return instance.second == Input::InputReleased;
}
template <typename Container>
static inline void Update(Container & container)
{
typedef typename Container::iterator Iter;
typedef typename Container::value_type TPair;
// Remove old data
Iter remove =
std::remove_if(container.begin(), container.end(), &CheckReleased<TPair>);
container.erase(remove, container.end());
// Update existing data
std::for_each(container.begin(), container.end(), &UpdateStates<TPair>);
}
/*******************************************************************************
* Input Implementation
******************************************************************************/
Input::InputState Input::keyState(Qt::Key k)
{
KeyContainer::iterator it = FindKey(k);
return (it != sg_keyInstances.end()) ? it->second : InputInvalid;
}
Input::InputState Input::buttonState(Qt::MouseButton k)
{
ButtonContainer::iterator it = FindButton(k);
return (it != sg_buttonInstances.end()) ? it->second : InputInvalid;
}
QPoint Input::mousePosition()
{
return QCursor::pos();
}
QPoint Input::mouseDelta()
{
return sg_mouseDelta;
}
void Input::update()
{
// Update Mouse Delta
sg_mousePrevPosition = sg_mouseCurrPosition;
sg_mouseCurrPosition = QCursor::pos();
sg_mouseDelta = sg_mouseCurrPosition - sg_mousePrevPosition;
// Update KeyState values
Update(sg_buttonInstances);
Update(sg_keyInstances);
}
void Input::registerKeyPress(int k)
{
KeyContainer::iterator it = FindKey((Qt::Key)k);
if (it == sg_keyInstances.end())
{
sg_keyInstances.push_back(KeyInstance((Qt::Key)k, InputRegistered));
}
}
void Input::registerKeyRelease(int k)
{
KeyContainer::iterator it = FindKey((Qt::Key)k);
if (it != sg_keyInstances.end())
{
it->second = InputUnregistered;
}
}
void Input::registerMousePress(Qt::MouseButton btn)
{
ButtonContainer::iterator it = FindButton(btn);
if (it == sg_buttonInstances.end())
{
sg_buttonInstances.push_back(ButtonInstance(btn, InputRegistered));
}
}
void Input::registerMouseRelease(Qt::MouseButton btn)
{
ButtonContainer::iterator it = FindButton(btn);
if (it != sg_buttonInstances.end())
{
it->second = InputUnregistered;
}
}
void Input::reset()
{
sg_keyInstances.clear();
sg_buttonInstances.clear();
}

63
lib/input.h

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Input class from tutorials followed at trentreed.net ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTOPENGL_INPUT_H
#define QTOPENGL_INPUT_H
#include <QPoint>
#include <Qt>
class Input {
friend class MainWidget;
public:
// Possible key states
enum InputState
{
InputInvalid,
InputRegistered,
InputUnregistered,
InputTriggered,
InputPressed,
InputReleased
};
// State checking
inline static bool keyTriggered(Qt::Key key)
{ return keyState(key) == InputTriggered;}
inline static bool keyPressed(Qt::Key key)
{ return keyState(key) == InputPressed;}
inline static bool keyReleased(Qt::Key key)
{ return keyState(key) == InputReleased;}
inline static bool buttonTriggered(Qt::MouseButton button)
{ return buttonState(button) == InputTriggered;}
inline static bool buttonPressed(Qt::MouseButton button)
{ return buttonState(button) == InputPressed;}
inline static bool buttonReleased(Qt::MouseButton button)
{ return buttonState(button) == InputReleased;}
// Implementation
static InputState keyState(Qt::Key key);
static InputState buttonState(Qt::MouseButton button);
static QPoint mousePosition();
static QPoint mouseDelta();
private:
// State updating
static void update();
static void registerKeyPress(int key);
static void registerKeyRelease(int key);
static void registerMousePress(Qt::MouseButton button);
static void registerMouseRelease(Qt::MouseButton button);
static void reset();
};
#endif // QTOPENGL_INPUT_H

1064
lib/mainwidget.cpp

File diff suppressed because it is too large Load Diff

84
lib/mainwidget.h

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Main window for Qt5 OpenGL widget application ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_MAINWIDGET_H
#define QTK_MAINWIDGET_H
#include <iostream>
#include <QMatrix4x4>
#include <QOpenGLDebugLogger>
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <camera3d.h>
#define QTK_DEBUG
class MeshRenderer;
class Model;
class Object;
class Skybox;
class Texture;
class MainWidget : public QOpenGLWidget,
protected QOpenGLFunctions {
Q_OBJECT;
public:
// Constructors
MainWidget();
explicit MainWidget(const QSurfaceFormat &format);
~MainWidget() override;
// Static Members
static inline QMatrix4x4 &Projection() { return mProjection;}
static inline Camera3D &Camera() { return mCamera;}
private:
void teardownGL();
void initObjects();
public:
// Inherited virtual Members
void paintGL() override;
void initializeGL() override;
void resizeGL(int width, int height) override;
protected slots:
void update();
void messageLogged(const QOpenGLDebugMessage &msg);
// Protected Helpers
protected:
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
// Private helpers
void printContextInformation();
void updateCameraInput();
// Private Members
static Camera3D mCamera;
static QMatrix4x4 mProjection;
Skybox * mSkybox;
Object * mObject;
MeshRenderer * mTestPhong;
MeshRenderer * mTestSpecular;
MeshRenderer * mTestDiffuse;
MeshRenderer * mTestAmbient;
std::vector<MeshRenderer *> mMeshes;
std::vector<Model *> mModels;
QOpenGLDebugLogger * mDebugLogger;
};
#endif // QTK_MAINWIDGET_H

336
lib/mesh.cpp

@ -0,0 +1,336 @@ @@ -0,0 +1,336 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Collection of static mesh data for quick initialization ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <mesh.h>
Cube::Cube(DrawMode mode)
{
mDrawMode = mode;
switch(mode) {
// Cube data for use with glDrawArrays
case QTK_DRAW_ARRAYS:
mIndices = { /* No indices needed for glDrawArrays */ };
mNormals =
{FACE_FRONT, FACE_BACK, FACE_TOP, FACE_BOTTOM, FACE_LEFT, FACE_RIGHT};
mVertices = {
// Face 1 (Front)
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL,
VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
// Face 2 (Back)
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR,
VERTEX_BTL, VERTEX_BBR, VERTEX_BBL,
// Face 3 (Top)
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL,
VERTEX_BTL, VERTEX_FTL, VERTEX_FTR,
// Face 4 (Bottom)
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
// Face 5 (Left)
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL,
VERTEX_FBL, VERTEX_BTL, VERTEX_BBL,
// Face 6 (Right)
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR,
VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
};
mColors = {
// Face 1 (Front)
RED, GREEN, BLUE,
BLUE, WHITE, RED,
// Face 2 (Back)
YELLOW, CYAN, MAGENTA,
CYAN, YELLOW, BLACK,
// Face 3 (Top)
RED, MAGENTA, CYAN,
CYAN, GREEN, RED,
// Face 4 (Bottom)
WHITE, BLUE, BLACK,
BLACK, YELLOW, WHITE,
// Face 5 (Left)
BLUE, GREEN, CYAN,
BLUE, CYAN, BLACK,
// Face 6 (Right)
RED, WHITE, YELLOW,
YELLOW, MAGENTA, RED
};
mTexCoords = {
// Face 1 (Front)
UV_TOP, UV_ORIGIN, UV_RIGHT,
UV_RIGHT, UV_CORNER, UV_TOP,
// Face 2 (Back)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 3 (Top)
UV_CORNER, UV_TOP, UV_ORIGIN,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Face 4 (Bottom)
UV_TOP, UV_ORIGIN, UV_RIGHT,
UV_RIGHT, UV_CORNER, UV_TOP,
// Face 5 (Left)
UV_TOP, UV_CORNER, UV_RIGHT,
UV_TOP, UV_RIGHT, UV_ORIGIN,
// Face 6 (Right)
UV_TOP, UV_CORNER, UV_RIGHT,
UV_RIGHT, UV_ORIGIN, UV_TOP
};
break;
// Cube data for use with glDrawElements
case QTK_DRAW_ELEMENTS:
mNormals =
{/* For normals and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
mTexCoords =
{ /* For UVs and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */ };
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
mVertices = {
// 0 1 2 3
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBR,
// 4 5 6 7
VERTEX_BTR, VERTEX_BTL, VERTEX_BBL, VERTEX_BBR
};
mIndices = {
// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
7, 5, 4, 5, 7, 6,
// Face 3 (Top)
0, 4, 5, 5, 1, 0,
// Face 4 (Bottom)
3, 2, 6, 6, 7, 3,
// Face 5 (Left)
2, 1, 5, 2, 5, 6,
// Face 6 (Right)
0, 3, 7, 7, 4, 0
};
break;
// Cube shape data for using normals and UVs with glDrawElements
case QTK_DRAW_ELEMENTS_NORMALS:
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
mVertices = {
// Face 1 (Front)
// 0 1 2 3
VERTEX_FTL, VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
// Face 2 (Back)
// 4 5 6 7
VERTEX_BTL, VERTEX_BBL, VERTEX_BBR, VERTEX_BTR,
// Face 3 (Top)
// 8 9 10 11
VERTEX_FTL, VERTEX_BTL, VERTEX_BTR, VERTEX_FTR,
// Face 4 (Bottom)
// 12 13 14 15
VERTEX_FBL, VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
// Face 5 (Left)
// 16 17 18 19
VERTEX_FBL, VERTEX_BBL, VERTEX_BTL, VERTEX_FTL,
// Face 6 (Right)
// 20 21 22 23
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
};
mIndices = {
// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
4, 5, 6, 6, 7, 4,
// Face 3 (Top)
8, 9, 10, 10, 11, 8,
// Face 4 (Bottom)
12, 13, 14, 14, 15, 12,
// Face 5 (Left)
16, 17, 18, 18, 19, 16,
// Face 6 (Right)
20, 21, 22, 22, 23, 20
};
mNormals = {
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD,
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK,
VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP,
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN,
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT,
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT,
};
mTexCoords = {
// Face 1 (Front)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 2 (Back)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 3 (Top)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 4 (Bottom)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 5 (Left)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 6 (Right)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
};
break;
}
}
Triangle::Triangle(DrawMode mode)
{
mDrawMode = mode;
const QVector3D triangleTop = QVector3D(0.0f, 0.5f, 0.0f);
switch(mode) {
case QTK_DRAW_ARRAYS:
mIndices = { /* No indices needed for glDrawArrays */ };
mColors = { RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK };
mVertices = {
// Bottom face (Base of the pyramid)
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
// Front face
VERTEX_FBL, VERTEX_FBR, triangleTop,
// Back face
VERTEX_BBR, VERTEX_BBL, triangleTop,
// Left face
VERTEX_BBL, VERTEX_FBL, triangleTop,
// Right face
VERTEX_FBR, VERTEX_BBR, triangleTop,
};
// Find normals for each triangle of the mesh
for (int i = 0; i < mVertices.size(); i += 3) {
QVector3D vertexNormal =
QVector3D::normal(mVertices[i], mVertices[i+1], mVertices[i+2]);
// Three points share this normal
for (int j = 0; j < 3; j++) {
mNormals.push_back(vertexNormal);
}
}
mTexCoords = {
// Bottom face (Base of the pyramid)
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_CORNER, UV_TOP, UV_ORIGIN,
// Front face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Back face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Left face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Right face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
};
break;
// Triangle shape data for using glDrawElements
case QTK_DRAW_ELEMENTS:
mColors = { RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK };
mVertices = {VERTEX_FBL, VERTEX_FBR, VERTEX_BBL, VERTEX_BBR, triangleTop};
mIndices = {
// Bottom face (Base of the pyramid)
2, 3, 1, // Use customVertexes[2], then 3, 1...
1, 0, 2, // Use customVertexes[1], then 0, 2
0, 1, 4, // Front face
3, 2, 4, // Back face
2, 0, 4, // Left face
1, 3, 4, // Right face
};
mNormals =
{/* Use QTK_DRAW_ELEMENTS_NORMALS for normals with glDrawElements */};
mTexCoords = { /* No UVs for triangle with glDrawElements */ };
break;
// Triangle shape data for using normals and UVs with glDrawElements
case QTK_DRAW_ELEMENTS_NORMALS:
mColors = { RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK };
mVertices = {
// Bottom face
// 0 1 2
VERTEX_FBL, VERTEX_FBR, VERTEX_BBL,
// 3 4 5
VERTEX_BBR, VERTEX_FBR, VERTEX_BBL,
// Front face
// 6 7 8
VERTEX_FBL, VERTEX_FBR, triangleTop,
// Back face
// 9 10 11
VERTEX_BBR, VERTEX_BBL, triangleTop,
// Left face
// 12 13 14
VERTEX_BBL, VERTEX_FBL, triangleTop,
// Right face
// 15 16 17
VERTEX_FBR, VERTEX_BBR, triangleTop,
};
mIndices = {
// Bottom face (Base of the pyramid)
0, 1, 2, // Use customVertexes[2], then 3, 1...
3, 4, 5, // Use customVertexes[1], then 0, 2
6, 7, 8, // Front face
9, 10, 11, // Back face
12, 13, 14, // Left face
15, 16, 17, // Right face
};
// Find normals for each triangle of the mesh
for (int i = 0; i < mVertices.size(); i += 3) {
QVector3D vertexNormal =
QVector3D::normal(mVertices[mIndices[i]],
mVertices[mIndices[i+1]],
mVertices[mIndices[i+2]]);
// Three points share this normal
for (int j = 0; j < 3; j++) {
mNormals.push_back(vertexNormal);
}
}
mTexCoords = {
// Bottom face
UV_ORIGIN, UV_RIGHT, UV_TOP,
UV_CORNER, UV_RIGHT, UV_TOP,
// Front face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Back face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Left face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Right face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
};
break;
}
}

131
lib/mesh.h

@ -0,0 +1,131 @@ @@ -0,0 +1,131 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Collection of static mesh data for quick initialization ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_MESH_H
#define QTK_MESH_H
#include <QOpenGLWidget>
#include <QVector2D>
#include <QVector3D>
#include <mainwidget.h>
#include <transform3D.h>
// Define vertices for drawing a cube using two faces (8 vertex points)
// Front Vertices
#define VERTEX_FTR QVector3D( 0.5f, 0.5f, 0.5f) // 1
#define VERTEX_FTL QVector3D(-0.5f, 0.5f, 0.5f) // 2
#define VERTEX_FBL QVector3D(-0.5f, -0.5f, 0.5f) // 3
#define VERTEX_FBR QVector3D( 0.5f, -0.5f, 0.5f) // 4
// Back Vertices
#define VERTEX_BTR QVector3D( 0.5f, 0.5f, -0.5f) // 5
#define VERTEX_BTL QVector3D(-0.5f, 0.5f, -0.5f) // 6
#define VERTEX_BBL QVector3D(-0.5f, -0.5f, -0.5f) // 7
#define VERTEX_BBR QVector3D( 0.5f, -0.5f, -0.5f) // 8
// Direction vectors
#define VECTOR_UP QVector3D(0.0f, 1.0f, 0.0f)
#define VECTOR_DOWN QVector3D(0.0f, -1.0f, 0.0f)
#define VECTOR_LEFT QVector3D(-1.0f, 0.0f, 0.0f)
#define VECTOR_RIGHT QVector3D(1.0f, 0.0f, 0.0f)
#define VECTOR_FORWARD QVector3D(0.0f, 0.0f, 1.0f)
#define VECTOR_BACK QVector3D(0.0f, 0.0f, -1.0f)
// Identity and zero vectors
#define VECTOR_ONE QVector3D(1.0f, 1.0f, 1.0f)
#define VECTOR_ZERO QVector3D(0.0f, 0.0f, 0.0f)
// A series of direction vectors to represent cube face normal
#define FACE_TOP VECTOR_UP, VECTOR_UP, VECTOR_UP, \
VECTOR_UP, VECTOR_UP, VECTOR_UP
#define FACE_BOTTOM VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, \
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
#define FACE_LEFT VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, \
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
#define FACE_RIGHT VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT
#define FACE_FRONT VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD
#define FACE_BACK VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, \
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
// Colors using QVector3Ds as RGB values
#define WHITE VECTOR_ONE
#define BLACK VECTOR_ZERO
#define RED QVector3D(1.0f, 0.0f, 0.0f)
#define GREEN QVector3D(0.0f, 1.0f, 0.0f)
#define BLUE QVector3D(0.0f, 0.0f, 1.0f)
#define YELLOW QVector3D(1.0f, 1.0f, 0.0f)
#define CYAN QVector3D(0.0f, 1.0f, 1.0f)
#define MAGENTA QVector3D(1.0f, 0.0f, 1.0f)
#define UV_ORIGIN QVector2D(0.0f, 0.0f)
#define UV_TOP QVector2D(1.0f, 0.0f)
#define UV_RIGHT QVector2D(0.0f, 1.0f)
#define UV_CORNER QVector2D(1.0f, 1.0f)
typedef std::vector<QVector3D> Vertices;
typedef std::vector<QVector3D> Colors;
typedef std::vector<GLuint> Indices;
typedef std::vector<QVector2D> TexCoords;
typedef std::vector<QVector3D> Normals;
enum DrawMode { QTK_DRAW_ARRAYS, QTK_DRAW_ELEMENTS, QTK_DRAW_ELEMENTS_NORMALS };
struct ShapeBase {
ShapeBase(DrawMode mode=QTK_DRAW_ARRAYS, Vertices v={},Indices i={}, Colors c={},
TexCoords t={}, Normals n={})
: mVertices(v), mColors(c), mIndices(i), mTexCoords(t), mNormals(n)
{}
inline const Vertices & vertices() const { return mVertices;}
inline const Indices & indices() const { return mIndices;}
inline const Colors & colors() const { return mColors;}
inline const TexCoords & texCoords() const { return mTexCoords;}
inline const Normals & normals() const { return mNormals;}
protected:
DrawMode mDrawMode;
Vertices mVertices;
Colors mColors;
Indices mIndices;
TexCoords mTexCoords;
Normals mNormals;
};
struct Shape : public ShapeBase {
friend MeshRenderer;
friend Object;
Shape () {}
Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
virtual inline void setVertices(const Vertices & value) {mVertices = value;}
virtual inline void setIndices(const Indices & value) {mIndices = value;}
virtual inline void setColors(const Colors & value) {mColors = value;}
virtual inline void setTexCoords(const TexCoords & value) {mTexCoords = value;}
virtual inline void setNormals(const Normals & value) {mNormals = value;}
virtual inline void setShape(const Shape & value) { *this = value;}
};
// Primitives inherit from ShapeBase, does not allow setting of shape values
class Mesh {
};
struct Cube : public ShapeBase {
Cube(DrawMode mode=QTK_DRAW_ARRAYS);
};
struct Triangle : public ShapeBase {
Triangle(DrawMode mode=QTK_DRAW_ARRAYS);
};
#endif // QTK_MESH_H

171
lib/meshrenderer.cpp

@ -0,0 +1,171 @@ @@ -0,0 +1,171 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: MeshRenderer class for quick object creation and drawing ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <QImageReader>
#include <texture.h>
#include <meshrenderer.h>
// Static QHash that holds all MeshRenderer instances using their mName as keys
MeshRenderer::MeshManager MeshRenderer::sInstances;
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape)
: Object(name, shape), mVertexShader(":/multi-color.vert"),
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES),
mHasTexture(false)
{
mShape = Shape(shape);
init();
sInstances.insert(name, this);
}
MeshRenderer::~MeshRenderer()
{
if (mHasTexture) {
mTexture->destroy();
}
sInstances.remove(mName);
}
// Static member function to retrieve instances of MeshRenderers
MeshRenderer * MeshRenderer::getInstance(const QString & name)
{ return sInstances[name];}
/*******************************************************************************
* Public Member Functions
******************************************************************************/
void MeshRenderer::init()
{
if (mVAO.isCreated()) mVAO.destroy();
if (mProgram.isLinked()) mProgram.removeAllShaders();
if (mVBO.isCreated()) mVBO.destroy();
mVAO.create();
mVAO.bind();
mProgram.create();
mProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,
mVertexShader.c_str());
mProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,
mFragmentShader.c_str());
mProgram.link();
mProgram.bind();
mVBO.create();
mVBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
mVBO.bind();
// Combine position and color data into one vector, allowing us to use one VBO
Vertices combined;
combined.reserve(vertices().size() + colors().size());
combined.insert(combined.end(), vertices().begin(), vertices().end());
combined.insert(combined.end(), colors().begin(), colors().end());
mVBO.allocate(combined.data(),
combined.size() * sizeof(combined[0]));
// Enable position attribute
mProgram.enableAttributeArray(0);
mProgram.setAttributeBuffer(0, GL_FLOAT, 0,
3, sizeof(QVector3D));
// Enable color attribute, setting offset to total size of vertices()
mProgram.enableAttributeArray(1);
mProgram.setAttributeBuffer(1, GL_FLOAT,
vertices().size() * sizeof(vertices()[0]),
3, sizeof(QVector3D));
mVBO.release();
mProgram.release();
mVAO.release();
}
void MeshRenderer::draw()
{
mProgram.bind();
mVAO.bind();
if(mHasTexture) {
mTexture->bind();
}
// TODO: Automate uniforms some other way
setUniformMVP();
if (mShape.mDrawMode == QTK_DRAW_ARRAYS) {
glDrawArrays(mDrawType, 0, vertices().size());
}
else if (mShape.mDrawMode == QTK_DRAW_ELEMENTS
|| mShape.mDrawMode == QTK_DRAW_ELEMENTS_NORMALS) {
glDrawElements(mDrawType, mShape.mIndices.size(),
GL_UNSIGNED_INT, mShape.mIndices.data());
}
if(mHasTexture) {
mTexture->release();
}
mVAO.release();
mProgram.release();
}
void MeshRenderer::setShaders(const std::string & vert, const std::string & frag)
{
mVertexShader = vert;
mFragmentShader = frag;
}
void MeshRenderer::setUniformMVP(const char * model, const char * view,
const char * projection)
{
mProgram.setUniformValue(projection, MainWidget::Projection());
mProgram.setUniformValue(view, MainWidget::Camera().toMatrix());
mProgram.setUniformValue(model, mTransform.toMatrix());
}
void MeshRenderer::setColor(const QVector3D & color)
{
if (mShape.mColors.empty()) {
for (const auto & vertex : mShape.vertices()) {
mShape.mColors.push_back(color);
}
}
else {
for (int i = 0; i < mShape.colors().size(); i++) {
mShape.mColors[i] = color;
}
}
}
void MeshRenderer::setTexture(const char * path)
{
mTexture = new QOpenGLTexture(*Texture::initImage(path));
mHasTexture = true;
}
void MeshRenderer::setTexture(QOpenGLTexture * texture)
{
mTexture = texture;
mHasTexture = true;
}
/*******************************************************************************
* Inherited Virtual Member Functions
******************************************************************************/
void MeshRenderer::setShape(const Shape & value)
{
Object::setShape(value);
init();
}

76
lib/meshrenderer.h

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: MeshRenderer class for quick object creation and drawing ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_MESHRENDERER_H
#define QTK_MESHRENDERER_H
#include <mesh.h>
#include <object.h>
class MeshRenderer : public Object {
public:
// Delegate constructors
MeshRenderer(const char * name, Vertices vertices, Indices indices,
DrawMode mode=QTK_DRAW_ARRAYS)
: MeshRenderer(name, ShapeBase(mode, vertices, indices))
{}
MeshRenderer(const char * name)
: MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS))
{}
// Constructor
MeshRenderer(const char * name, const ShapeBase &shape);
~MeshRenderer();
// Retrieve a mesh by name stored within a static QHash
static MeshRenderer * getInstance(const QString & name);
void init();
void draw();
// Draw types like GL_TRIANGLES, GL_POINTS, GL_LINES, etc
void setDrawType(int drawType) { mDrawType = drawType;}
// Shader settings
inline void setShaderVertex(const std::string & vert) { mVertexShader = vert;}
inline void setShaderFragment(const std::string & frag) { mFragmentShader = frag;}
void setShaders(const std::string & vert, const std::string & frag);
template <typename T>
inline void setUniform(int location, T value)
{ mProgram.setUniformValue(location, value);}
template <typename T>
inline void setUniform(const char * location, T value)
{ mProgram.setUniformValue(location, value);}
// Set MVP matrix using this Object's transform
// + View and projection provided by MainWidget static members
void setUniformMVP(const char * model="uModel", const char *